Beruflich Dokumente
Kultur Dokumente
From An Experts Guide to Oracle Technology I have been coding for a long time and have pretty much seen it all. Today I present 9 tips for becoming a master programmer. If you follow these tips, people will stare at you as you walk by. They will talk about you around water coolers. Your code will be used as an example in code reviews. Of this I promise!
WARNING: Humor, sarcasm, and a bit of whimsy abounds below.
Tip #1: Use No Indentation Yes, I know you have probably heard that indentation is a good thing. Wrong! Indentation just leads to arguments. Should it be 3 spaces or 4? What about 2 spaces? What about tabs? Should I indent here or there. Bah! Take a stand sissy! No more indentation. Youll be edgy and cool. When you cut and paste into forums and someone tells you to use a special forum command to maintain your indentation, smugly inform them that IT DID maintain your indentation. Tip #2: All Caps Capital letters are bigger. Bigger is easier to see. Easier to see is easier to maintain. CODE IN ALL CAPS = GOOD! Tip #3: Name All Variables var Obviously, you cant name all of your variables var. PL/SQL wont let you have 2 variables of the same name. So, what do I mean? Add a number. Var1, Var2, Var3, etc. Oops. Forgot my naming standard. L_var1, l_var2, l_var3 (never v_! Thats crazy talk). Some will say that you should give meaningful names to your variables. Pfft. That would make sense if it werent for tip #4. Tip #4: Reuse variables Reuse is good. I read that all over the place. How do we get maximum reuse? Create as few variables as possible. As soon as you are finished with a variable, you can reuse it in another context. For example, I have the code below. It is using 3 variables. What a waste. With a little creative coding, I can get that down to a single variable. Simplification and reuse, FTW! NOTE: I am ignoring tips 1 and 2 for this example. Dont do this in your code!
DECLARE v_var1 VARCHAR2(100); v_var2 VARCHAR2(100); v_var3 VARCHAR2(100); BEGIN SELECT salary INTO v_var1 FROM employees WHERE last_name = 'Smith'; v_var2 := v_var1 + 100; v_var3 := sysdate; DBMS_OUTPUT.PUT_LINE('Smith salary was raised from: ' ||
See how much easier that is to read when it's not all cluttered up with variables. Tip #5: All variables character, let Oracle translate for you! I just showed you this tip in Tip #4. All variables are VARCHAR2 columns. I bet you didn't know that Oracle would convert all of your data types back and forth for you, did you? Yep, it sure will. There is no reason to concern yourself with data types! You're a coder, not a weenie DB guy. Look at my example above. I was able to reuse a variable for strings, numbers and dates. Sweet! Tip #6: Exceptions as flow control A program moves forward through the code right? An exception moves you forward right? So what is the best way to get from here to there? RAISE! Yep, RAISE. I don't think there is a faster way to jump to a new point in code than an exception. Especially in a really long procedure. But how can I go backwards? Why use a GOTO silly! What a dumb question. I shouldn't even have to tell you that! Here is an example:
DECLARE v_var1 v_var2 BEGIN SELECT INTO FROM VARCHAR2(100); VARCHAR2(100); some_data v_var1 a_table;
<<get_magic_number>> BEGIN SELECT magic_number INTO v_var2 FROM ultimate_lookup_table; IF v_var1 = v_var2 THEN RAISE_APPLICATION_ERROR(-20001, 'Whee!'); ELSE DBMS_OUTPUT.PUT_LINE('The numbers don''t match.'); INSERT INTO dontmatch VALUES (v_var1, v_var2); END IF; EXCEPTION WHEN OTHERS THEN IF sqlcode = -20001 THEN UPDATE ultimate_lookup_table SET magic_number = v_var1; GOTO get_magic_number; ELSE NULL; END IF; END; END;
Tip #7: One procedure This is a tip that is not followed often enough. I see people writing "modular" code all the time. You know what "modular" means? It means you end up with a bunch of files and procedures and finding where your errors are is really hard. I read somewhere that it was like 70% harder to search in multiple files than in 1 file. There is really no reason why any application needs more than 1 procedure. The way to make a procedure do it all is to add any possible parameter to the procedure and code logic to run the needed functionality. Below is a very simple example. I have to declare multiple parameters since I want to handle all of the input but that is a necessary evil. The great part is that the parameters can be reused depending on what the procedure is called for. This could get much larger but I am keeping simple for the example.
create or replace PROCEDURE doesitall( p_param1 IN VARCHAR2 DEFAULT NULL, p_param2 IN VARCHAR2 DEFAULT NULL, p_param3 IN VARCHAR2 DEFAULT NULL, p_param4 IN VARCHAR2 DEFAULT NULL, p_param5 IN VARCHAR2 DEFAULT NULL, p_param6 IN VARCHAR2 DEFAULT NULL, p_param7 IN VARCHAR2 DEFAULT NULL, p_param8 IN VARCHAR2 DEFAULT NULL, p_param9 IN VARCHAR2 DEFAULT NULL, p_param10 IN VARCHAR2 DEFAULT NULL ) AS v_var1 VARCHAR2(100);
v_var2 VARCHAR2(100); BEGIN IF p_param2 = 'Get Magic Number' THEN SELECT some_data INTO v_var1 FROM a_table WHERE p_param5 = '6'; <<get_magic_number>> BEGIN SELECT magic_number INTO v_var2 FROM ultimate_lookup_table; IF v_var1 = v_var2 THEN RAISE_APPLICATION_ERROR(-20001, 'Oops'); ELSE DBMS_OUTPUT.PUT_LINE('The numbers don''t match.'); INSERT INTO dontmatch VALUES (v_var1, v_var2); END IF; EXCEPTION WHEN OTHERS THEN IF sqlcode = -20001 THEN UPDATE ultimate_lookup_table SET magic_number = v_var1; GOTO get_magic_number; ELSE NULL; END IF; END; ELSIF p_param1 = 'Loop 10 times' THEN DECLARE v_var1 VARCHAR2(100); BEGIN v_var1 := 1; <<loop_label>> IF v_var1 < 11 THEN GOTO loop_label; END IF; END; END IF; END;
Tip #8: Packages with public variables One tip that will make you the master is to use packages. Oracle offers this awesome tool for making global variables. It's called a package. Don't even bother using parameters or variables. Just put everything in one global package. It makes maintenance so easy because you never need to declare anything in your code. Just use a package variable. And reuse? Yeah baby! Every application in a
database can reuse the globals. Heck, your application procedure can reuse the same variables in different blocks. Here is the previous example recoded for maximum reuse. I am keeping it small for the example but there is no reason your global package can't be 1000 or more globals. And if you have big data, just make all the variables as CLOBS or VARCHAR2(32767). Whichever works best for you.
CREATE OR REPLACE PACKAGE global_variables AS g_var1 VARCHAR2(100); g_var2 VARCHAR2(100); g_var3 VARCHAR2(100); g_var4 VARCHAR2(100); g_var5 VARCHAR2(100); g_var6 VARCHAR2(100); g_var7 VARCHAR2(100); g_var8 VARCHAR2(100); g_var9 VARCHAR2(100); g_var10 VARCHAR2(100); g_var11 VARCHAR2(100); g_var12 VARCHAR2(100); g_var13 VARCHAR2(100); g_var14 VARCHAR2(100); g_var15 VARCHAR2(100); g_var16 VARCHAR2(100); END; create or replace PROCEDURE doesitall AS BEGIN IF global_variables.g_var4 = 'Get Magic Number' THEN SELECT some_data INTO global_variables.g_var1 FROM a_table WHERE global_variables.g_var5 = '6'; <<get_magic_number>> BEGIN SELECT magic_number INTO global_variables.g_var2 FROM ultimate_lookup_table; IF global_variables.g_var1 = global_variables.g_var2 THEN RAISE_APPLICATION_ERROR(-20001, 'Oops'); ELSE DBMS_OUTPUT.PUT_LINE('The numbers don''t match.'); INSERT INTO dontmatch VALUES (global_variables.g_var1, global_variables.g_var2); END IF; EXCEPTION WHEN OTHERS THEN IF sqlcode = -20001 THEN UPDATE ultimate_lookup_table SET magic_number = global_variables.g_var1;
GOTO get_magic_number; ELSE NULL; END IF; END; ELSIF global_variables.g_var6 = 'Loop 10 times' THEN BEGIN global_variables.g_var15 := 1; <<loop_label>> IF global_variables.g_var15 < 11 THEN GOTO loop_label; END IF; END; END IF; END;
Tip #9: Semi colon is the statement terminator. Use it. Put logical statements on the same line. That way you'll know where to cut so you can paste it other places later. So far, in my examples, I have not been following my own tips. I did this because I know you have had to deal with such bad code that reading good code would be hard for you. Well, you need to get on board! Below is my last bit of code (the doesitall procedure) but this time it follows all of my tips. Isn't it awesome!
CREATE OR REPLACE PROCEDURE DOESITALL AS BEGIN IF GLOBAL_VARIABLES.G_VAR4 = 'Get Magic Number' THEN SELECT SOME_DATA INTO GLOBAL_VARIABLES.G_VAR1 FROM A_TABLE WHERE GLOBAL_VARIABLES.G_VAR5 = '6'; <<GET_MAGIC_NUMBER>> BEGIN SELECT MAGIC_NUMBER INTO GLOBAL_VARIABLES.G_VAR2 FROM ULTIMATE_LOOKUP_TABLE; IF GLOBAL_VARIABLES.G_VAR1 = GLOBAL_VARIABLES.G_VAR2 THEN RAISE_APPLICATION_ERROR(20001, 'Oops'); ELSE DBMS_OUTPUT.PUT_LINE('The numbers don''t match.'); INSERT INTO DONTMATCH VALUES (GLOBAL_VARIABLES.G_VAR1, GLOBAL_VARIABLES.G_VAR2); END IF; EXCEPTION WHEN OTHERS THEN IF SQLCODE = -20001 THEN UPDATE ULTIMATE_LOOKUP_TABLE SET MAGIC_NUMBER = GLOBAL_VARIABLES.G_VAR1; GOTO GET_MAGIC_NUMBER; ELSE NULL; END IF; END; ELSIF GLOBAL_VARIABLES.G_VAR6 = 'Loop 10 times' THEN BEGIN GLOBAL_VARIABLES.G_VAR15 := 1; <<LOOP_LABEL>> IF GLOBAL_VARIABLES.G_VAR15 < 11 THEN GOTO LOOP_LABEL; END IF; END; END IF; END;
All of that in just 11 lines of code! I rock so hard! Take care, LewisC P.S. All of this code runs/compiles. If you run this code, be prepared. Endless loops be thar!