Disciplined PL/SQL

本文分享了四位简单实用的编程指南,旨在帮助PL/SQL开发者提高代码质量和可维护性。指南包括遵循命名规范、减少直接使用SQL、限制执行块大小及建立伙伴审查制度。

Disciplined PL/SQL

By Steven Feuerstein

Four simple guidelines for improving the quantity and quality of PL/SQL code you write

I have been writing PL/SQL code since 1990. This means I have churned out tens of thousands of lines of software, and most of it, I am certain, was poorly written and difficult to maintain.

Fortunately, I have discovered that it is never too late to find—and follow—new paths to writing better code. In just the past year, the quality of my code has improved significantly; this improvement has come mostly from setting some simple rules and then following them in a disciplined way.

This article offers four pieces of advice for novice and experienced PL/SQL developers; follow any of these suggestions and your code will improve. Follow all of them, and you likely will be struck by the sudden realization that you are a much better programmer than you ever thought possible.

All by Yourself

Few of us work in isolation; most PL/SQL development takes place in relatively large organizations. Yet we are still, by and large, left to our own devices, working alone in our own cubicles. Hardly any PL/SQL development teams engage in formal code review or systematic testing.

I cannot, through this magazine article, change the fundamental dynamics in your development team. I have, therefore, chosen the following points of advice carefully. You will not need to obtain management approval to implement any of them. You won't have to get everyone on your team, whether it's large or small, to agree to the same coding guidelines. Instead, you can concentrate on doing nothing more than transforming your personal coding experience by following these suggestions:

1. Follow naming conventions as though your life depended on it.
2. Break your SQL addiction: The less SQL you write, the better.
3. Keep your executable sections small: Say goodbye to "spaghetti code."
4. Find a buddy: Come to love the idea of having someone looking over your shoulder.

1. Follow Naming Conventions

If you establish and follow rigorously a set of naming conventions, particularly for your application components, you will be able to save lots of time.

Of course, the idea of following naming conventions is nothing new, and it probably sounds boring to you. So rather than propose any grand naming schemes, I will be very concrete and specific, and then I will demonstrate to you how useful such conventions can be.

I have spent the last few months designing and constructing a new tool for PL/SQL developers. It is called Swyg (available at www.swyg.com), and it helps programmers through code generation, testing, and reuse. It therefore has several distinct components. I decided to assign a two-letter abbreviation to each component as follows:

SF—Swyg foundation elements
SM—Swyg metadata
SG—Swyg generator
SL—Swyg code library
ST—Swyg unit testing

I then followed the naming conventions in Table 1, using these abbreviations. What advantages accrue to following such conventions? Very generally, if I am consistent about how I name things, I can write my code more smoothly and productively.

Specifically, the predictability of the conventions means I can write SQL programs that generate useful scripts. For example, using the conventions in Table 1, I can generate an installation script for all of my base packages in Swyg. The SQL*Plus script that does all the work for me appears in Listing 1. This sort of script is handy, because it means I do not have to maintain the installation script manually. When I add another table to the Swyg schema and generate the related set of packages, I simply run my script, and out pops the updated installation script.

2. Break Your SQL Addiction

As counterintuitive as this might seem, the less SQL you write, the better. This is strange advice for a PL/SQL developer, because one of the key advantages of PL/SQL is the ease of writing SQL statements in your code. This ease, however, is also an Achilles' heel of the language.

You can place native SQL statements directly inside PL/SQL code; no intermediate layers such as JDBC or ODBC are necessary. Consequently, PL/SQL developers generally embed SQL statements whenever and wherever they need them in their application code. So what's wrong with that?

Dispersion of SQL statements in PL/SQL code leads inevitably to the following:

  • Repetition of the same logical statement, although with different physical representations, resulting in excessive parsing and difficulty in optimizing the performance of your application.
  • Exposure of business rules and formulas. There is a good chance that you will include right in the SQL statement logic that implements business rules. Such rules, of course, are always changing, so the maintenance costs of your application rise rapidly.

Of course, just about every PL/SQL application you will write is built on underlying tables and views. You need to execute SQL statements. The question is not if, but when and how.

Your application will be much more robust, and you will find it much easier to build and maintain, if you encapsulate your data structures, or hide them behind a layer of PL/SQL code, usually a package.

Let's look at a simple example. Suppose I need to write a program that processes an employee. The first thing I need to do is get the full name of that employee, defined as "last comma (,) first"; I can then perform the detailed analysis. Listing 2 offers an example of the sort of code I am likely to write in this situation.

It all seems so simple and direct; what could possibly be wrong with this code? An awful lot, actually. Most important, I have exposed a business rule: the structure of a full name. I can test this code, and the application it is built on, for hours. Right after it goes into production, however, I just know that I will be getting calls from users telling me that, in actuality, they need their full names to be presented as "last space first."

What now? Search for all occurrences of a single comma inside quotation marks?<!---->

The real solution is to use packages that hide all these details and simply provide a set of predefined, pretested, and preoptimized programs that do all the work for me. Listing 3 shows a rewriting of the process_employee procedure based on encapsulated code. The hr_employee_tp package provides the type I use to define the local variable holding the name; the hr_employee_rp package contains the function that returns the full name, based on a business rule.

Just as it is easy to dump explicit SQL statements into PL/SQL code, it is also easy to talk about how important it is to encapsulate those statements. It is challenging, on the other hand, to write the code that performs the encapsulation; it is likely not even practical to do so. Perhaps generating these packages makes more sense.

I helped build such a generator several years ago. It is called PL/Generator, and in a special arrangement with Quest Software (the current owner of PL/Generator), it is now available at no charge to the PL/SQL development community. You can download it from my Web site by visiting www.StevenFeuerstein.com/puter/gencentral.htm. Be aware that its encapsulation architecture is different from the convention I outlined earlier in this article. PL/Generator creates a single package that contains all of the type, query, and change logic for a table.

Whether you generate or write your own custom encapsulations, your applications will benefit greatly when you stop writing so much SQL and instead call the programs that execute the SQL for you.

3. Keep Your Executable Sections Small

Let's face it: All too often, against our better judgment and our latest round of New Year's resolutions, we end up writing spaghetti code: large, endless blobs of meandering code that are virtually impossible to understand, much less maintain or enhance. What can you do to avoid spaghetti?

Actually, the solution is simple: Never allow an executable section to exceed more than 50 or 60 lines. This size allows you to view the entire logical structure of the block on a single page of paper or eyeful of screen, which also means that you can actually grasp the intention of the program and understand it at a fairly intuitive level.

You may well agree with all of this yet scoff at my suggestion that your world could ever be contained in 50 lines of code. You should scoff, because that is, of course, not possible. You will no doubt need more than 50 lines of executable code; the question is where you will put that code and how you will organize it.

You will indeed be able to implement requirements of arbitrary complexity and hew to the 50-line limit, if you

  • Take care to reuse code whenever possible by placing all business rules and discrete chunks of logic in their own programs (usually functions)
  • Make extensive use of local modules, procedures and functions that are defined right inside the declaration section of your program

Suppose I am working on a call center application. I have been told to write a program whose documentation contains this overview:

"For every employee in the specified department, compare that person's workload (the number of calls assigned to the employee) with the average load for an employee in that department. If the employee is underutilized, assign the next open call to that person and schedule an appointment to work on that case."

From previous work on this system, I know that my friend Claudia has written an analysis package that returns information on workload. But assigning open calls and scheduling appointments are both new tasks, defined in detail in the rest of the requirements document.

My first inclination is to read through the entire 15 pages of information, but I resist. Instead, I use a "stepwise refinement" or "top-down design" technique and take my first stab at implementing the program by writing the code in Listing 4.

The following offers an explanation of the most pertinent lines in Listing 4; I'm starting from the bottom of the program (the compact executable section) and working my way up. This may sound counterintuitive, but it is actually the best way to read through a program that was written with stepwise refinement.

Lines 22-30. I use a cursor FOR loop to iterate through all the employees in the specified department. In lines 24-25, I take advantage of the analysis package's programs to determine if the current employee is underutilized. In lines 27-28, I type in calls to three programs: assign_next_open_case, schedule_case, and next_appointment. I don't know yet what I will have to do to implement these programs, but I know they express through their names and the parameter list what I need to have done.

Lines 10-19. I create "stubs," or placeholder programs, for the three programs in lines 27-28. Note that these are local modules, defined within assign_workload and not callable from any other program.

Lines 5-8. I define a cursor to get all the employees in the specified department. I can now try to compile this code.

Getting a clean compile on such a small program may seem like a small victory, and it is. But small victories such as these—a clean compile, then a simple test, then the addition of a bit more code, another clean compile, and so on—lead to well-constructed programs and a big dose of satisfaction.

I can also verify that the analysis programs work and identify the appropriate employees for assignment. Once all this is done, I will pick one of my three programs, say assign_next_open_case, for my next step or level of refinement. I read the documentation for that task and write a simple, small executable section within assign_next_open_case that reflects the overview of that task.

Soon, my local procedure has its own local procedures and functions, but at every step of the way, my code is short, readable, easily tested, and fixable as needed.

4. Find a Buddy

Computers do not write programs; humans write them.

How many times have you sat hunched over your computer, deeply frustrated by your inability to find a bug in your code? First minutes and then hours pass. Finally, disgusted with yourself and feeling like a failure, you poke your head over the top of your cubicle and ask a friend to come over and take a look.

One of three things usually happens:

  • As the friend gets up from her chair, all becomes instantly clear.
  • Your friend takes one peek at the screen and immediately puts her finger on the problem.
  • Your friend doesn't work on your area of the system, so you have to explain what your program is doing. As you step through the logic, the flaw that is causing the bug pops out at you.

The reality is that it's hard to debug your own code, because you are too attached to and too involved in it.

Next Steps

READ
more on Oracle Database 10g
oracle.com/database

more articles by Feuerstein
otn.oracle.com/oramag/webcolumns/2003

The best solution to this problem is for the development manager to create a culture in which ideas are shared, ignorance is admitted without penalty, and constructive code reviews take place regularly. Such cultural changes are, unfortunately, difficult to achieve.

In the meantime, I suggest that you take the first steps in helping transform the culture in your group. Seek out another developer, preferably one with more experience than you, and establish a "buddy" relationship: Offer to be a sounding board for that person in case of problems if your buddy will do the same for you. Agree in advance that there isn't anything wrong with not knowing the answer to everything.

Then set a simple rule for yourself: Never struggle for more than half an hour on a bug. When 30 minutes have passed, call your buddy over and put human psychology to work for you, not against you.

Four Steps to a New Way

This article offered four steps you can take, without investing in new tools or changing overall group process, to transform your coding experience. You don't even have to follow all four steps; the benefits accrue independently.

Steven Feuerstein (steven@stevenfeuerstein.com) is an authority on the PL/SQL language. Feuerstein is the author of nine books on PL/SQL (all from O'Reilly & Associates), including Oracle PL/SQL Best Practices and Oracle PL/SQL Programming. He is also a senior technology advisor for Quest Software.

ObjectStructure of NameNotesCreation (DDL) file
Table <abbrev>_<entity>Name of table, such as SM_TASK, for tasks defined in the general Mentat component.<abbrev>_<entity>.tab
Primary key columnidThe standard is that (almost) every table contains an id column generated by a sequence. There are some exceptions for intersection tables and the like.N/A
Sequence for generating a primary key<abbrev>_<entity>_seqName of sequence for the primary key on a table, such as SG_SCRIPT_SEQ, which generates a new primary key for the Mentat generation script table.<abbrev>_<entity>.seq
Query encapsulation package<abbrev>_<entity>_qpContains standard APIs for retrieving data from an underlying table, such as SL_SOURCE_QP, which helps me query the source code for elements in the Mentat reusable library. Specification: <abbrev>_<entity>_qp.pks
Body: <abbrev>_<entity>_qp.pkb
Change encapsulation package<abbrev>_<entity>_cpContains standard APIs for changing (INSERT, UPDATE, DELETE) data in an underlying table, such as ST_UNITTEST_CP, which allows me to maintain unit test definitions. Specification: <abbrev>_<entity>_cp.pkb
Body: <abbrev>_<entity>_cp.pks
Types encapsulation package<abbrev>_<entity>_tpContains predefined types—including collections, the REF CURSORS, and records—for specified table, such as SG_GEN_RUN_TP. Specification: <abbrev>_<entity>_tp.pks
Body: NA (type definitions do not need a package body)
Rules encapsulation package <abbrev>_<entity>_rpContains programs, usually functions, that hide the details of the business rules associated with this entity. Specification: <abbrev>_<entity>_rp.pks
Body: <abbrev>_<entity>_rp.pkb
Extra stuff package<abbrev>_<entity>_xpContains custom logic for a particular entity. Specification: <abbrev>_<entity>_xp.pks
Body: <abbrev>_<entity>_xp.pkb

Key
  • <abbrev> is the two-letter abbreviation. For Swyg, it is either SF, SM, SG, SL, or ST.
  • <entity> is the name of the business entity, such as TASK, for defining one's "to do list" of tasks; SCRIPT, for code generation templates; and so on.
内容概要:本文详细介绍了一个基于Java和Vue的联邦学习隐私保护推荐系统的设计与实现。系统采用联邦学习架构,使用户数据在本地完成模型训练,仅上传加密后的模型参数或梯度,通过中心服务器进行联邦平均聚合,从而实现数据隐私保护与协同建模的双重目标。项目涵盖完整的系统架构设计,包括本地模型训练、中心参数聚合、安全通信、前后端解耦、推荐算法插件化等模块,并结合差分隐私与同态加密等技术强化安全性。同时,系统通过Vue前端实现用户行为采集与个性化推荐展示,Java后端支撑高并发服务与日志处理,形成“本地训练—参数上传—全局聚合—模型下发—个性化微调”的完整闭环。文中还提供了关键模块的代码示例,如特征提取、模型聚合、加密上传等,增强了项目的可实施性与工程参考价值。 适合人群:具备一定Java和Vue开发基础,熟悉Spring Boot、RESTful API、分布式系统或机器学习相关技术,从事推荐系统、隐私计算或全栈开发方向的研发人员。 使用场景及目标:①学习联邦学习在推荐系统中的工程落地方法;②掌握隐私保护机制(如加密传输、差分隐私)与模型聚合技术的集成;③构建高安全、可扩展的分布式推荐系统原型;④实现前后端协同的个性化推荐闭环系统。 阅读建议:建议结合代码示例深入理解联邦学习流程,重点关注本地训练与全局聚合的协同逻辑,同时可基于项目架构进行算法替换与功能扩展,适用于科研验证与工业级系统原型开发。
源码来自:https://pan.quark.cn/s/a4b39357ea24 遗传算法 - 简书 遗传算法的理论是根据达尔文进化论而设计出来的算法: 人类是朝着好的方向(最优解)进化,进化过程中,会自动选择优良基因,淘汰劣等基因。 遗传算法(英语:genetic algorithm (GA) )是计算数学中用于解决最佳化的搜索算法,是进化算法的一种。 进化算法最初是借鉴了进化生物学中的一些现象而发展起来的,这些现象包括遗传、突变、自然选择、杂交等。 搜索算法的共同特征为: 首先组成一组候选解 依据某些适应性条件测算这些候选解的适应度 根据适应度保留某些候选解,放弃其他候选解 对保留的候选解进行某些操作,生成新的候选解 遗传算法流程 遗传算法的一般步骤 my_fitness函数 评估每条染色体所对应个体的适应度 升序排列适应度评估值,选出 前 parent_number 个 个体作为 待选 parent 种群(适应度函数的值越小越好) 从 待选 parent 种群 中随机选择 2 个个体作为父方和母方。 抽取父母双方的染色体,进行交叉,产生 2 个子代。 (交叉概率) 对子代(parent + 生成的 child)的染色体进行变异。 (变异概率) 重复3,4,5步骤,直到新种群(parentnumber + childnumber)的产生。 循环以上步骤直至找到满意的解。 名词解释 交叉概率:两个个体进行交配的概率。 例如,交配概率为0.8,则80%的“夫妻”会生育后代。 变异概率:所有的基因中发生变异的占总体的比例。 GA函数 适应度函数 适应度函数由解决的问题决定。 举一个平方和的例子。 简单的平方和问题 求函数的最小值,其中每个变量的取值区间都是 [-1, ...
当GPS驯服振荡器(GPS Disciplined Oscillator, GPSDO)的1PPS(每秒一个脉冲)信号丢失时,系统会进入一种“自由运行”或“保持模式”。在该状态下,GPSDO不再能够通过外部1PPS信号校准其内部振荡器的频率和相位。此时,振荡器的行为将依赖于其自身的稳定性和之前积累的校正数据。 在失去1PPS信号的情况下,GPSDO通常会利用最后已知的校正值对内部振荡器进行补偿,以尽量维持输出信号的准确性。然而,随着时间推移,由于环境变化、老化等因素导致的频率漂移,内部振荡器的误差将逐渐增加[^1]。不同质量的振荡器在断开1PPS后的稳定性差异较大,例如恒温控制晶体振荡器(OCXO)通常比温度补偿晶体振荡器(TCXO)具有更好的短期稳定性和更低的漂移率。 为了应对1PPS信号丢失的情况,可以采取以下措施: - **启用保持模式**:现代GPSDO设备通常具备保持模式功能,在此模式下,设备会使用历史数据预测并维持频率偏移,从而在有限时间内保持较高的时间精度[^2]。 - **监控与告警机制**:部署实时监控系统来检测1PPS信号的状态,并在信号丢失时触发告警,以便及时采取人工干预或其他补救措施。 - **冗余设计**:采用多路输入源或者备用时间同步源(如网络时间协议NTP服务器、其他GNSS系统等),确保主1PPS信号失效时有替代方案可用。 - **定期校准**:即使在正常操作期间,也应定期执行手动或自动校准过程,以更新振荡器的偏差参数,提高断开后的保持性能。 此外,一些高级GPSDO模块还支持智能恢复功能,能够在重新接收到有效1PPS信号后快速调整回准确的时间基准,减少再同步所需的时间。 ### 示例代码 以下是一个简单的Python脚本示例,用于模拟GPSDO在1PPS信号丢失前后的行为变化: ```python import time class GPSDO: def __init__(self): self.gps_locked = True self.frequency_error = 0.0 # in Hz def simulate_1pps_loss(self): print("1PPS signal lost.") self.gps_locked = False # Simulate drift over time without correction for i in range(5): # Simulate 5 seconds of free run if not self.gps_locked: self.frequency_error += 0.001 # Arbitrary drift rate print(f"Time since loss: {i+1}s, Estimated error: {self.frequency_error}Hz") time.sleep(1) def restore_1pps(self): print("1PPS signal restored.") self.gps_locked = True self.frequency_error = 0.0 print("Re-synchronizing to GPS... Done.") # Create instance and test behavior gpsdo = GPSDO() gpsdo.simulate_1pps_loss() gpsdo.restore_1pps() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值