Anda di halaman 1dari 34

Say Goodbye to Hard-Coding

in Your PL/SQL Programs

Steven Feuerstein
PL/SQL Evangelist, Quest Software
steven.feuerstein@quest.com
Copyright 2000-2009 Steven Feuerstein - Page 1
How to benefit most from this session

 Watch, listen, focus on concepts and principles.


 Download and use any of my the training materials:
PL/SQL Obsession http://www.ToadWorld.com/SF

 Download and use any of my scripts (examples,


performance scripts, reusable code) from the
same location: the demo.zip file. filename_from_demo_zip.sql

 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!
Copyright 2000-2006 Steven Feuerstein - Page 2
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


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
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
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


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
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


Where's the hard-coding?
1 PROCEDURE process_employee (department_id_in IN NUMBER)
2 IS
3 l_id NUMBER (9, 2); l_salary NUMBER;
4 l_name VARCHAR2 (100);
5
6 /* Full name: LAST COMMA FIRST (ReqDoc 123.A.47) */
7 CURSOR emps_in_dept_cur
8 IS
9 SELECT employee_id, salary, last_name || ',' || first_name lname
10 FROM employees
11 WHERE department_id = department_id_in;
12 BEGIN
13 OPEN emps_in_dept_cur;
14
15 LOOP
16 FETCH emps_in_dept_cur
17 INTO l_id, l_salary, l_name;
18
19 IF l_salary > 10000000
20 THEN
21 must_be_ceo;
22 END IF;
23
24 analyze_compensation (l_id, l_salary);
25 EXIT WHEN emps_in_dept_cur%NOTFOUND;
26 END LOOP;
27* END;
Copyright 2000-2008 Steven Feuerstein - Page 9
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
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


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.

thisuser*.*
Copyright 2000-2008 Steven Feuerstein - Page 12
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.

soft_code_literals.sql
Copyright 2000-2008 Steven Feuerstein - Page 13
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


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.

15
Applying SUBTYPEs

 Instead of this:
DECLARE
l_full_name VARCHAR2(100);
l_big_string VARCHAR2(32767);

 You would write this:


DECLARE
l_full_name employees_rp.full_name_t;
l_big_string plsql_limits.maxvarchar2;

fullname.pks
plsql_limits.pks
string_tracker3.*
Copyright 2000-2008 Steven Feuerstein - Page 16
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


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.
DECLARE
l_start_time PLS_INTEGER;
BEGIN
l_start_time := DBMS_UTILITY.get_time;
-- Do stuff here...
DBMS_OUTPUT.put_line (DBMS_UTILITY.get_time – l_start_time);
END;

And yet so wrong...

get_time.sql
sf_timer.*
Copyright 2000-2008 Steven Feuerstein - Page 18
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


How can SQL be hard coding?

 I need to write a three way join to return HR


information for a report.
SELECT . . .
FROM employees, departments, locations
WHERE . . . (a page full of complex conditions)

 And Joe needs to use that same query in his


business rule procedure. And so on...
 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!
Copyright 2000-2008 Steven Feuerstein - Page 20
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.

Copyright 2000-2008 Steven Feuerstein - Page 21


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 Application


Code
defined in the data access layer.
– Known as table APIs, transaction APIS, Intermediate Layer
or data encapsulation, these programs
contain all the intelligence about
business transactions and underlying Order Item
Table Table
tables.

Copyright 2000-2008 Steven Feuerstein - Page 22


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.

Copyright 2000-2008 Steven Feuerstein - Page 23


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>_XP qu_outcome_xp.qu_outcomes
qu_outcome_xp.int_create_outcomes

Copyright 2000-2008 Steven Feuerstein - Page 24


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

Copyright 2000-2008 Steven Feuerstein - Page 25


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


Logging Errors

 We usually, but not always, want to write error


information out to a log table. How's this?
WHEN NO_DATA_FOUND THEN
l_code := SQLCODE;
INSERT INTO errlog
VALUES ( l_code
, 'No company for id ' || TO_CHAR ( v_id )
, 'fixdebt', SYSDATE, USER );
WHEN OTHERS THEN
l_code := SQLCODE; l_errm := SQLERRM;
INSERT INTO errlog
VALUES (l_code, l_errm, 'fixdebt', SYSDATE, USER );
RAISE;
END;

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


the logging mechanism.
Copyright 2000-2008 Steven Feuerstein - Page 27
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.
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;

Copyright 2000-2008 Steven Feuerstein - Page 28


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
Function Result Cache Example
CREATE OR REPLACE PACKAGE emplu11g
IS
FUNCTION onerow (employee_id_in IN employees.employee_id%TYPE)
RETURN employees%ROWTYPE
RESULT_CACHE;
END emplu11g;

CREATE OR REPLACE PACKAGE BODY emplu11g


IS
FUNCTION onerow (employee_id_in IN employees.employee_id%TYPE)
RETURN employees%ROWTYPE
RESULT_CACHE RELIES_ON (employees)
IS
onerow_rec employees%ROWTYPE;
BEGIN
SELECT * INTO onerow_rec
FROM employees
WHERE employee_id = employee_id_in;

RETURN onerow_rec;
END onerow;
END emplu11g;

30
11g_emplu.pkg
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.

string_tracker3.*
cc_smartargs.pkb
Copyright 2000-2008 Steven Feuerstein - Page 31
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.
32
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
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

Anda mungkin juga menyukai