... it would work”. Refactoring SQL Applications, Stéphan Faroult ... Refactoring
Goals and Focus Areas. • APEX Focus ... store static files outside of DB. • Reduce
...
Refactoring Application Express Greg Jarmiolowski SQLPrompt LLC
1
Refactoring Application Express • “Too often the design is determined by the first way everyone agrees it would work” Refactoring SQL Applications, Stéphan Faroult
2
Refactoring Application Express • • • • • • •
What is Refactoring Refactoring Goals and Focus Areas APEX Focus Areas for Refactoring Finding What to Refactor Strategies and Challenges Process Overview Example Refactorings 3
What is Refactoring • Stepwise Refinement • Not just tuning • Not intended to provide new functionality BUT • It can lay groundwork for new functionality • Evolution = Adapt or Die “An effective architecture is one in which the most likely changes are also the easiest to make.” Software architecture in practice, Len Bass 4
What is Refactoring in APEX • In APEX code is organized within a framework • Rewriting code goes hand in hand with reorganizing the application • APEX architecture informs choices
5
If it ain’t broke…Why Refactor Immediate Needs Future Goals • Security • Extend functionality • Performance • UI Changes – AJAX ~80% of effort in systems occurs after • Simplify deployment maintenance • Scalability • Data integrity 6
Refactoring Goals • • • • • • •
Simplify Enhance performance Take advantage of new features Enhance security Scalability Reusability – Decoupling Specific vs. Generic 7
Coding Practice Goals • Reduce – Redundant Code – Dynamic SQL – HTML in SQL and PL/SQL
• • • •
Small Code Units Stored Object Names SPODIFICATION Adopt a Meta Data Mindset 8
Goals and Strategies Goal
Strategy
Performance
Inter-element Communication
Modifiability
Element Responsibilities
Security
Inter-Element Communication
Scalability
Localization of Resources
Ability to Subset
Inter-Element Usage
Reusability
Inter-Element Coupling
Source: Carnegie Mellon Software Engineering Institute
9
Simplification Look for opportunities to SPODIFY • Conditions • Application Items • Application Computations • Application Processes • Report SQL
10
Performance • Caching – Region Cache – SQL Cache Hint (11g) – Function Result Cache (11g) • Statement Tuning
11
Take Advantage of New Features Take advantage of new features in APEX • WWV_FLOW_ASSERT • APEX_UTIL.JSON_FROM_XX • JavaScript APIs (apex_ns_3_1.js) Prepare for new features in Application • Data Access Layer API • Application Processes 12
Security • • • •
SQL Injection VPD LDAP Integration Single Sign On
13
Scalability Closely related to performance • Localization of Resources • Session State Data • PPR/Cascading LOVs • Use of Static Files – one big file vs several smaller ones – store static files outside of DB
• Reduce Network Trips • Reduce Individual DB Reads 14
Reusability Decoupling • Stored predicates • Rules Manager/Expression Filter • Queues and Jobs • APIs encapsulating tables • Web Services • Workflow • AJAX – URI dependence 15
Decoupling - Rules Manager/Expression Filter
16
Specific vs. Generic • Generalization – Adds flexibility – Increases centralization • Specificity – Can enhance performance – Can ease troubleshooting 17
Refactoring APEX How can refactoring be applied to APEX? • Examine APEX architecture • Look for crossover functionality • Look for opportunities to SPODIFY
18
APEX Architecture 19
Refactoring APEX • • • • •
Explore the Architecture Look for crossover functionality Use APEX views and application reports Look for side effects Consider page lifecycle
20
APEX Refactorings • • • • • •
Items – Page, App, Temp Conditions Processes – Auto vs. PL/SQL Validations Branches Computations
21
APEX Refactorings • • • •
Reports Regions – HTP vs. Template JavaScript - AJAX Globalization
22
APEX Refactorings •
Items – Page, App, Temporary – Replacing page items with Application Items – Replacing page items in AJAX calls with temporary items • addGlobals()
23
APEX Refactorings Conditions • Conditions are everywhere • Perfect for centralizing with boolean functions
24
APEX Refactorings Processes – Auto vs. PL/SQL • Automatic DML and Row Fetch – Very flexible – Built-in optimistic locking – Item to column mapping – Lacks logging – No control over errors – Auto row fetched data not persisted* *http://c2anton.blogspot.com/2008/12/oracle-application-express-apex-three.html 25
APEX Refactorings Validations • Ordering and short circuiting • Reduce redundancy • Not much crossover • Extract logic into computation
26
APEX Refactorings Branches • Use of ITEM vs Page number – App Level Item vs Page Level
• •
New set session state option Ordering and short circuiting
27
APEX Refactorings Computations • Reduce redundancy with a process • Combine calls to the same table – Set values in a process
28
APEX Refactorings Reports • Replace dynamic SQL source • Move HTML to column attributes and templates • Simplify SQL with DB view • Reusable predicates • SQL calculated attributes • APEX_COLLECTION 29
APEX Refactorings Regions • HTP vs. Template • Go beyond HTP.P – Htp.anchor – Htp.tablexxx • APEX_ITEM – Updatable Report • Translatable text 30
APEX Refactorings JavaScript – AJAX • $ functions • apex.ajax.ondemand • AddArrayItems() • AddPageItems() • APEX_UTIL.JSON_FROM_SQL • $d_LOV_from_JSON 31
AJAX – URL Decoupling f?p
wwv_flow.show
App
p_flow_id
Page
p_flow_step_id
Session
p_instance
Request
p_request
Debug
p_debug
Clear Cache
p_clear_cache
Item Names
p_arg_names
Item Values
p_arg_values
PrinterFriendly
p_printer_friendly
$a_report() - APEX PPR pagination and sorting function var l_URL = 'p='+$v('pFlowId')+':'+$v('pFlowSte pId')+':'+$v('pInstance')+':FLOW_P PR_OUTPUT_R'+pId+'_'; … var ajax = new htmldb_Get(null,null,null,null,null,'f',l _URL); var gReturn = ajax.get();
32
APEX Refactorings Globalization • APEX_LANG • Text Messages – Shared Items -> Globalization
33
Finding What to Refactor • • • • •
Beauty of APEX is the metadata APEX Component Reports APEX Views Object Dependencies Page “Referenced” View
34
Finding What to Refactor Hack the Object Depenendencies Report APEX_030200.wwv_flow_theme_files.find_obj ect_dependencies (p_flow_id=>:P1_APP_ID, p_page_id=>null);
• Need to grant rights to package
35
Finding What to Refactor select SEQ_ID AS ORDER_SEQ , C001 AS schema_name , C002 AS object_name , C003 AS object_type , C004 AS component_name , C005 AS page_number , C006 AS component_id , C007 AS component_source , C008 AS app_id , C009 AS bound_items , C010 AS component_type , C011 AS component_source_type from htmldb_collections where c008 = :P1_APP_ID and c002 'PLITBLM' and collection_name = 'ALL_DEPENDENCIES' 36
Finding What to Refactor
37
Strategies • • • • • • •
Decide goals Determine scope Choose methods Create plan Test Document Release 38
Strategies Important Considerations • System owner needs • System owner capabilities • Future changes and growth • System owner buy in “Every design decision comes down to cost, benefit, and risk” The Data Model Resource Book - Volume 3, Len Silverston 39
Strategies System Owner Considerations • Capabilities and capacity • Complexity of resultant architecture • Maintenance of resultant system • Administration of resultant system New processes, scheduled jobs • Exception reporting 40
Strategies Future changes and growth • How far do you go in anticipating the progression of needs • Does the system require more or less flexibility in design • Consider reusing or integrating subsets
41
Strategies Getting Buy In • Original developer objections • Time vs. Benefit • Low Hanging Fruit • Don’t estimate performance gains • Prove inefficiencies
42
Strategies • • • •
Smaller changes are easier Break your work into smaller tasks Determine scope of changes The greater the coupling the harder the refactoring • Track changes carefully
43
Strategies Measuring your work • How will you measure progress? • What metrics go with your goals? • Can you build instrumentation from your analysis tools?
44
Process Overview • • • • • • •
Determine refactoring(s) needed Choose the method(s) Determine the scope Create a new version with changes Test Document Release 45
Example Refactorings Add a column to the database • Add column to db • Add item to page • Set the db column attributes - Auto Fetch and Auto DML • OR • Add column to fetch or calculation • Add column to DML process 46
Example Refactorings Replace SQL Exists condition with function • SQL Conditions might seem innocuous in the beginning but once your data grows you might begin to see a performance hit • If this filtered on an un-indexed column or it includes a function call performance can suffer • Conditionals are often redundant 47
Example Refactorings Replace condition with authorization scheme • If the condition relies on user dependent attributes alone it is a good candidate for an authorization scheme • Probably an even better candidate for a stored function • An even better candidate for 11g Function Result Cache 48
Example Refactorings Replace page process with on demand application process • May entail the creation of app items • New app items need to have values set • Extends possibilities for using AJAX
49
Example Refactorings Replace multiple branches with process to set target page and branch to it • May reduce redundant calls to functions within branch conditions • Good way to reduce function and/or query based conditions • Puts page branch logic in one block • Eliminates the problem of a branch reordering causing unexpected results 50
Example Refactorings Replace Dynamic SQL with Static SQL • Variable column lists can be made conditional in the report attributes • Variable table lists might indicate a bigger problem with your design
51
Example Refactorings Replace Dynamic SQL with Static SQL • Consider the use of CASE for nested conditionals
• Think beyond “this column equals that” • Case construct allows nested conditions – if this is true then check these other things • Put null conditions first to take advantage of short-circuit evaluation • Order conditions from most to least true 52
Example Refactorings Example using CASE for where conditions SELECT * FROM my_table WHERE 1 = CASE WHEN :G_SEC_LEV < 3 AND :G_FACILITY_ID = 0 THEN CASE WHEN region_id = :G_REGION_ID THEN 1 ELSE 0 END WHEN :G_SEC_LEV < 3 AND :G_FACILITY_ID != 0 THEN CASE WHEN facility_id = :G_FACILITY_ID THEN 1 ELSE 0 END WHEN :P69_REGION_ID != 0 THEN CASE WHEN region_id = :G_REGION_ID THEN 1 ELSE 0 END ELSE 1 END
53
Example Refactorings Example using CASE for columns SELECT CASE WHEN INSTR(':' || sec_lev || ':' , ':' || :G_SEC_LEV || ':')>0 THEN CASE WHEN next_sec_lev IS NOT NULL THEN '
PUSH' WHEN next_sec_lev IS NULL THEN '
Submit' 54
Example Refactorings CASE statement constructs Given mutually exclusive conditions a-d within 100 records The ordering of the evaluation affects the total number of evaluations CONDITION TRUE FALSE # EVALS a 10 90 100 b 20 80 90 c 30 70 70 d 40 60 40 total records -> 100 300
CONDITION d c b a total records ->
TRUE 40 30 20 10 100
FALSE 60 70 80 90
# EVALS 100 60 30 10 200 55
Example Refactorings
Replace Automated Row Fetch with PL/SQL expression • Automated Row Fetch doesn’t persist session state • No data is not an error • Consider using record types FUNCTION get_emp(empid IN NUMBER) RETURN employee%ROWTYPE; DECLARE emp_rec employee%ROWTYPE; BEGIN emp_rec := get_emp(:PX_EMPID); :PX_emp_lname := emp_rec.lname; 56
Example Refactorings Replace Automatic DML with PL/SQL • Allows for custom error handling • Consider (again) using record types PROCEDURE update_emp(empid IN employee%ROWTYPE); DECLARE emp_rec employee%ROWTYPE; BEGIN emp_rec.emp_id : = :PX_EMPID; emp_rec.lname := :PX_EMP_LNAME; … update_emp(emp_rec); 57
Example Refactorings Rewriting Conditions • Conditions are everywhere • Reduce redundancy • Reduce use of session state (items) • May need to find PL/SQL equivalents for unique condition types – Current Page = Page Submitted 58
Example Refactorings Conditions are everywhere • • • • • • • • • • • • • • • •
APEX_APPLICATION_BC_ENTRIES APEX_APPLICATION_COMPUTATIONS APEX_APPLICATION_LIST_ENTRIES APEX_APPLICATION_LOV_ENTRIES APEX_APPLICATION_NAV_BAR APEX_APPLICATION_PAGES APEX_APPLICATION_PAGE_BRANCHES APEX_APPLICATION_PAGE_BUTTONS APEX_APPLICATION_PAGE_COMP APEX_APPLICATION_PAGE_IR APEX_APPLICATION_PAGE_IR_COL APEX_APPLICATION_PAGE_IR_COND APEX_APPLICATION_PAGE_ITEMS APEX_APPLICATION_PAGE_PROC APEX_APPLICATION_PAGE_REGIONS APEX_APPLICATION_PAGE_RPT_COLS
• • • • • • • • • • • • • • • •
APEX_APPLICATION_PAGE_VAL APEX_APPLICATION_PARENT_TABS APEX_APPLICATION_PROCESSES APEX_APPLICATION_SHORTCUTS APEX_APPLICATION_TABS WWV_FLOW_LIST_ITEMS WWV_FLOW_MENU_OPTIONS WWV_FLOW_PAGE_PLUGS WWV_FLOW_REGION_REPORT_COLUMN WWV_FLOW_REGION_REPORT_FILTER WWV_FLOW_STEPS (Cache condition) WWV_FLOW_STEP_BRANCHES WWV_FLOW_STEP_BUTTONS WWV_FLOW_STEP_VALIDATIONS WWV_FLOW_TABS WWV_FLOW_TOPLEVEL_TABS
59
Example Refactorings Replacing Conditions with Authorizations • Can be evaluated per session or page view • Can be subscribed to for sharing across applications • Can be reused in Conditions apex_util.public_check_authorization (‘AUTHORIZATION_SCHEME_NAME’)
• Can be reset as needed (all or nothing) apex_util.reset_authorizations 60
Example Refactorings Replacing Conditions with Authorizations • Available for the following components – – – – – – – – – – – – – –
Application Computation Navigation Bar List Items Breadcrumb Entry Region Process (page and app level) Report Column Page Branch Button Item Validation Tab 61
Example Refactorings Replacing Item Level LOV with shared LOV • WWV_FLOW_STEP_ITEMS.LOV Shows LOVs defined at item level
62
Suggested Reading
Refactoring Databases: Evolutionary Database Design Scott W. Ambler and Pramodkumar J. Sadalage
63
Suggested Reading
Refactoring SQL Applications Stephane Faroult and Pascal L'Hermite
64
Suggested Reading
Oracle PL/SQL Best Practices Steven Feuerstein
65
Refactoring Application Express Greg Jarmiolowski SQLPrompt LLC
66