Say Goodbye to Hard-Coding

34
Copyright 2000-2009 Steven Feuerstein - Page 1 Say Goodbye to Hard-Coding in Your PL/SQL Programs Steven Feuerstein PL/SQL Evangelist, Quest Software [email protected]

Transcript of Say Goodbye to Hard-Coding

Page 1: Say Goodbye to Hard-Coding

Copyright 2000-2009 Steven Feuerstein - Page 1

Say Goodbye to Hard-Coding

in Your PL/SQL Programs

Steven FeuersteinPL/SQL Evangelist, Quest Software

[email protected]

Page 2: Say Goodbye to Hard-Coding

Copyright 2000-2006 Steven Feuerstein - Page 2

How to benefit most from this session

Watch, listen, focus on concepts and principles.

Download and use any of my the training materials:

You have my permission to use all these materials to do internal trainings and build your own applications.– But remember: they are not production ready.

– Modify them to fit your needs and then test them!

filename_from_demo_zip.sql

Download and use any of my scripts (examples, performance scripts, reusable code) from the same location: the demo.zip file.

http://www.ToadWorld.com/SFPL/SQL Obsession

Page 3: Say Goodbye to Hard-Coding

Say Goodbye to Hard-Coding

What is hard-coding?

Why is it a problem?

Soft Coding and Easy Coding

Identify all sorts of hard-coding in PL/SQL

Specific techniques for getting rid of those

hard-codings

Copyright 2000-2008 Steven Feuerstein - Page 3

Page 4: Say Goodbye to Hard-Coding

What is Hard Coding? - 1

Traditionally, has referred to practice of

placing literal values in the main body of your

code.– From Wikipedia: The term "hard-coded" was coined in

1990 by R. Galichon (then a Programmer/Analyst at

Mobil). The term was used as an analogy to hardwiring

circuits - and was meant to convey the inflexibility which

results from its usage within software design and

implementation.

More generally, hard-coding is closely tied to

the problem of repetition in our code.

Copyright 2000-2008 Steven Feuerstein - Page 4

Page 5: Say Goodbye to Hard-Coding

What is Hard Coding? - 2

You "hard code" every time you write a piece

of code that assumes an aspect of your

application will not change and therefore can

be explicitly referenced throughout the code

base.

Then when the change takes place, you have

to locate all those repetitions and fix them.

– Sometimes that's easy, sometimes it is very

difficult to do, but in all cases, it causes

problems.

Copyright 2000-2008 Steven Feuerstein - Page 5

Page 6: Say Goodbye to Hard-Coding

Why is Hard Coding Bad?

Hard-coding would be fine if nothing ever

changed in our applications.

– If requirements stayed the same...

– If the definitions of our tables stayed the same....

– If rules and formulas stayed the same....

– If configuration constants stayed the same....

Too bad!

– Whenever anything changes, you have to find all

the places you explicitly coded it, and fix them.

Copyright 2000-2008 Steven Feuerstein - Page 6

Page 7: Say Goodbye to Hard-Coding

Soft Coding and Easy Coding

If hard-coding is bad, then maybe we should

do the opposite of hard-coding.

Soft Coding

– Rather than explicitly code values, rules and

algorithms, make them "soft" or dynamic –

changeable and settable at runtime.

Easy Coding

– It's hard fixing hard-codings in multiple places.

It'd be easier to fix things in one place. It really

does make things easier.

Copyright 2000-2008 Steven Feuerstein - Page 7

Page 8: Say Goodbye to Hard-Coding

Hard-Coding Avoidance: Principles and Concepts

Single point of definition (no repetition)

– You should always aim for a single point of definition or

SPOD for everything in your application.

Information hiding – the name is the thing

– Avoid exposing the implementation details of formulas,

rules, algorithms, data access.

– The more you hide, the more flexibility you have.

"Never" and "Always" in software

– It's never going to stay the same.

– It's always going to change.

Copyright 2000-2008 Steven Feuerstein - Page 8

Page 9: Say Goodbye to Hard-Coding

Where's the hard-coding?

Copyright 2000-2008 Steven Feuerstein - Page 9

1 PROCEDURE process_employee (department_id_in IN NUMBER)2 IS3 l_id NUMBER (9, 2); l_salary NUMBER;4 l_name VARCHAR2 (100);56 /* Full name: LAST COMMA FIRST (ReqDoc 123.A.47) */7 CURSOR emps_in_dept_cur8 IS9 SELECT employee_id, salary, last_name || ',' || first_name lname

10 FROM employees11 WHERE department_id = department_id_in;12 BEGIN13 OPEN emps_in_dept_cur;1415 LOOP16 FETCH emps_in_dept_cur17 INTO l_id, l_salary, l_name;1819 IF l_salary > 1000000020 THEN21 must_be_ceo;22 END IF;2324 analyze_compensation (l_id, l_salary);25 EXIT WHEN emps_in_dept_cur%NOTFOUND;26 END LOOP;27* END;

Page 10: Say Goodbye to Hard-Coding

Potential Hard-Codings in PL/SQL Code

Literal values

– Especially language-specific literals

Constrained declarations

– Especially VARCHAR2(n)

Fetch into a list of variables

Rules and formulas

– Especially the "trivial" ones

SQL statements

– ??? Very scary to contemplate – to be explained later

Algorithmic details

– Example: error logging mechanisms

Copyright 2000-2008 Steven Feuerstein - Page 10

Page 11: Say Goodbye to Hard-Coding

Literal Values

The most commonly recognized form of

hard-coding.

The only place a literal should appear in your

code is in its SPOD.

Hide literals behind:

– constants

– functions

Or soft code in tables.

Copyright 2000-2008 Steven Feuerstein - Page 11

Page 12: Say Goodbye to Hard-Coding

Constants vs. Functions

Constants are simple and quick, but they

expose the value in the package specification.

– If the value needs to change, all programs that

depend on that package must be recompiled.

Put the value behind a function and then it is

hidden.

– When the value changes, only the package body

must be recompiled.

– But this is less efficient than a constant.

Copyright 2000-2008 Steven Feuerstein - Page 12thisuser*.*

Page 13: Say Goodbye to Hard-Coding

Soft-Code Values in Table

You can make things really flexible by putting

all literals in a table, associating them with a

name, and retrieving them as needed from

the table.

Downsides are:

– More complex code

– More overhead, but caching can avoid this

problem.

Copyright 2000-2008 Steven Feuerstein - Page 13

soft_code_literals.sql

Page 14: Say Goodbye to Hard-Coding

Constrained Declarations

You should consider every declaration of the

form VARCHAR2(N) to be a bug.

– Unless it is the SPOD for that type.

Instead, anchor the declaration back to its

"source".

– %TYPE for variables based on columns

– %ROWTYPE for records based on table/cursor

– SUBTYPES for all applications-specific types

Copyright 2000-2008 Steven Feuerstein - Page 14

Page 15: Say Goodbye to Hard-Coding

15

SUBTYPEs

Most everyone knows about %TYPE and

%ROWTYPE.

– But what if you can't anchor back to a DB element?

You can always use a SUBTYPE to define a "single

point of definition" and use that for all subsequent

declarations.

SUBTYPEs allow you to give application-specific

names to types.

– Critical when working with complex structures like

collections of records, and nested collections.

Page 16: Say Goodbye to Hard-Coding

Applying SUBTYPEs

Instead of this:

Copyright 2000-2008 Steven Feuerstein - Page 16

DECLAREl_full_name VARCHAR2(100);l_big_string VARCHAR2(32767);

You would write this:

DECLAREl_full_name employees_rp.full_name_t;l_big_string plsql_limits.maxvarchar2;

fullname.pks

plsql_limits.pks

string_tracker3.*

Page 17: Say Goodbye to Hard-Coding

Rules and Formulas

Much more critical than repeated literals.

What we know about rules and formulas:

– They will change.

– They will get more complex.

What to do?

– Learn to recognize rules and formulas. Often

they are missed, especially when simple.

– Hide the logic behind functions.

Copyright 2000-2008 Steven Feuerstein - Page 17

Page 18: Say Goodbye to Hard-Coding

Example: Never trust a rule!

Oracle offers DBMS_UTILITY.GET_TIME and

GET_CPU_TIME (10g) to compute elapsed

time down to the hundredth of a second.

Copyright 2000-2008 Steven Feuerstein - Page 18

DECLAREl_start_time PLS_INTEGER;

BEGINl_start_time := DBMS_UTILITY.get_time;-- Do stuff here...DBMS_OUTPUT.put_line (DBMS_UTILITY.get_time – l_start_time);

END;

get_time.sql

sf_timer.*

And yet so wrong...

Page 19: Say Goodbye to Hard-Coding

SQL Statements

Why do I talk about SQL in a presentation on

hard coding?

Because I believe that every SQL statement

that you write is a hard-coding!

– I know, it is shocking to contemplate.

So what am I talking about?

Copyright 2000-2008 Steven Feuerstein - Page 19

Page 20: Say Goodbye to Hard-Coding

How can SQL be hard coding?

I need to write a three way join to return HR

information for a report.

Copyright 2000-2008 Steven Feuerstein - Page 20

SELECT . . .FROM employees, departments, locations

WHERE . . . (a page full of complex conditions)

And then the three way join turns into a four

way join – and we have to find all occurrences

of this query.

– A very tough thing to do!

And Joe needs to use that same query in his

business rule procedure. And so on...

Page 21: Say Goodbye to Hard-Coding

Copyright 2000-2008 Steven Feuerstein - Page 21

What to do about SQL hard coding

Of course, you have to (and should) write

SQL statements in your PL/SQL code.

– PL/SQL is, in fact, the best place for SQL.

But we should be very careful about where,

when and how we write these statements.

– Follow the principles; they are your guide.

– Don't repeat anything!

The best approach: hide SQL inside a data

access layer.

Page 22: Say Goodbye to Hard-Coding

Copyright 2000-2008 Steven Feuerstein - Page 22

SQL as a Service

Think of SQL as a service that is provided to you, not

something you write.

– Or if you write it, you put it somewhere so that it can be

easily found, reused, and maintained.

This service consists of programs

defined in the data access layer.

– Known as table APIs, transaction APIS,

or data encapsulation, these programs

contain all the intelligence about

business transactions and underlying

tables.

Order

Table

Item

Table

Application

Code

Intermediate Layer

Page 23: Say Goodbye to Hard-Coding

Copyright 2000-2008 Steven Feuerstein - Page 23

With a data access layer, I can...

Change/improve my implementation with minimal impact on my application code.

– The underlying data model is constantly changing.

– We can depend on Oracle to add new features.

– We learn new ways to take advantage of PL/SQL.

Vastly improve my SQL-related error handling.

– Do you handle dup_val_on_index for INSERTs, too_many_rows for SELECT INTOs, etc?

Greatly increase my productivity

– I want to spend as much time as possible implementing business requirements.

Page 24: Say Goodbye to Hard-Coding

Copyright 2000-2008 Steven Feuerstein - Page 24

Example: Quest Code Tester backend

For each table, we have

three generated packages:

– <table>_CP for DML

– <table>_QP for queries

– <table>_TP for types

And usually an "extra stuff"

package with custom SQL

logic and related code:

– <table>_XPqu_outcome_xp.qu_outcomes

qu_outcome_xp.int_create_outcomes

Page 25: Say Goodbye to Hard-Coding

Copyright 2000-2008 Steven Feuerstein - Page 25

How to implement data encapsulation

It must be very consistent, well-designed and efficient

- or it will not be used.

Best solution: generate as much of the code as

possible.

– And any custom SQL statements should be written once

and placed in a standard container (usually a package).

Powerful and free option for generating table APIs for

use with PL/SQL is the freeware Quest CodeGen

Utility.

Quest CodeGen Utility: www.ToadWorld.com/SF

Page 26: Say Goodbye to Hard-Coding

Hide algorithmic details

Even if the users don't change their minds,

we (developers) and Oracle technology

change.

So assume that whatever you are working on

will change – and hide it behind an API.

– Logging errors

– Function result cache

– Manipulating collection contents

Copyright 2000-2008 Steven Feuerstein - Page 26

Page 27: Say Goodbye to Hard-Coding

Logging Errors

We usually, but not always, want to write error

information out to a log table. How's this?

Copyright 2000-2008 Steven Feuerstein - Page 27

WHEN NO_DATA_FOUND THENl_code := SQLCODE;INSERT INTO errlogVALUES ( l_code

, 'No company for id ' || TO_CHAR ( v_id ), 'fixdebt', SYSDATE, USER );

WHEN OTHERS THENl_code := SQLCODE; l_errm := SQLERRM;INSERT INTO errlogVALUES (l_code, l_errm, 'fixdebt', SYSDATE, USER );

RAISE;END;

It's easy to "read" but only because it exposes

the logging mechanism.

Page 28: Say Goodbye to Hard-Coding

Hide how and what you log: shared, generic logging utility

This rewrite is based on the Quest Error

Manager.

– Freeware available at www.ToadWorld.com/SF.

– You do less work and get more information.

Copyright 2000-2008 Steven Feuerstein - Page 28

WHEN NO_DATA_FOUND THEN

q$error_manager.register_error (text_in => 'No company for id ' || TO_CHAR ( v_id ));

WHEN OTHERS THEN

q$error_manager.raise_unanticipated (name1_in => 'COMPANY_ID', value1_in => v_id);

END;

Page 29: Say Goodbye to Hard-Coding

The Oracle11g function result cache

The optimal way to query and cache data

changes over time.

– Explicit and implicit cursors

– FORALL and BULK COLLECT

– And now the function result cache

With the Result Cache, you specify

declaratively that Oracle not run your function

over and over for the same inputs.

– Instead return the data previously cached with

matching inputs.

Copyright 2000-2008 Steven Feuerstein - Page 29

Page 30: Say Goodbye to Hard-Coding

30

Function Result Cache Example

CREATE OR REPLACE PACKAGE emplu11gIS

FUNCTION onerow (employee_id_in IN employees.employee_id%TYPE)RETURN employees%ROWTYPERESULT_CACHE;

END emplu11g;

CREATE OR REPLACE PACKAGE BODY emplu11gIS

FUNCTION onerow (employee_id_in IN employees.employee_id%TYPE)RETURN employees%ROWTYPERESULT_CACHE RELIES_ON (employees)

ISonerow_rec employees%ROWTYPE;

BEGINSELECT * INTO onerow_recFROM employeesWHERE employee_id = employee_id_in;

RETURN onerow_rec;END onerow;

END emplu11g;

11g_emplu.pkg

Page 31: Say Goodbye to Hard-Coding

Manipulating collection contents

Collections are Oracle's version of arrays in

PL/SQL.

– A relatively complicated but critically important

datatype.

Best to hide collection references behind

procedures and functions.

– Especially when you work with string-indexed

and multi-level collections.

Copyright 2000-2008 Steven Feuerstein - Page 31

string_tracker3.*

cc_smartargs.pkb

Page 32: Say Goodbye to Hard-Coding

32

Hiding stuff – a great career move!

By hiding my SQL statements (and all other

forms of hard-coding) behind subprograms, I

am in a good position to....

Hide my mistakes– Does the query have a bug in it? OK, fix the one instance of

the query inside my function. I don't have to tell everyone

about it....

Get a promotion– I can improve my application code much more quickly than

those who hard-code SQL.....

– The Result Cache is a great example of this.

Page 33: Say Goodbye to Hard-Coding

Say goodbye to hard coding!

It's not all that difficult to do, once you

recognize all the different ways that hard

coding can manifest itself in your code.

Repeat nothing: become allergic to

redundant repetition.

Aim for a "single point of definition" in

everything you write.

Hide, hide, hide: values, implementations,

workarounds

Copyright 2000-2008 Steven Feuerstein - Page 33

Page 34: Say Goodbye to Hard-Coding

Your Reward

Elegant, functional code that you and others

can maintain easily

The respect of your peers

A deep sense of satisfaction with a job well

done

The opportunity to continue making a darned

good living mostly from just thinking about

stuff.

Copyright 2000-2008 Steven Feuerstein - Page 34