The important thing is to recognise and resist the temptation of the Utilities package. The name itself (and similarly vague synonyms like helper or utils) should be a red flag. When we find ourselves about to type create or replace package utilities
we need to stop and think: what would be a better name for this package? Consider whether there are related functions we might end up needing? Suppose we're about to write a function to convert a date into Unix epoch string. It doesn't take much imagine to think we might need a similar function to convert a Unix timestamp into a date. We don't need to write that function now but let's start a package dedicated to Time functions instead of a miscellaneous utils package.
Looking closely at the programs which comprise the DBMS_UTILITY
package it is obviously unfair to describe them as a random selection. In fact that there seven or eight groups of related procedures.
DB Info
INSTANCE_RECORD
Record TypeDBLINK_ARRAY
Table TypeINSTANCE_TABLE
Table TypeACTIVE_INSTANCES
ProcedureCURRENT_INSTANCE
FunctionDATA_BLOCK_ADDRESS_BLOCK
FunctionDATA_BLOCK_ADDRESS_FILE
FunctionDB_VERSION
ProcedureGET_ENDIANNESS
FunctionGET_PARAMETER_VALUE
FunctionIS_CLUSTER_DATABASE
FunctionMAKE_DATA_BLOCK_ADDRESS
FunctionPORT_STRING
Function
FORMAT_CALL_STACK
FunctionFORMAT_ERROR_BACKTRACE
FunctionFORMAT_ERROR_STACK
Function
COMMA_TO_TABLE
ProceduresCOMPILE_SCHEMA
ProcedureCREATE_ALTER_TYPE_ERROR_TABLE
ProcedureINVALIDATE
ProcedureTABLE_TO_COMMA
ProceduresVALIDATE
Procedure
INDEX_TABLE_TYPE
Table TypeLNAME_ARRAY
Table TypeNAME_ARRAY
Table TypeNUMBER_ARRAY
Table TypeUNCL_ARRAY
Table TypeCANONICALIZE
ProcedureGET_DEPENDENCY
ProcedureNAME_RESOLVE
ProcedureNAME_TOKENIZE
Procedure
OLD_CURRENT_SCHEMA
FunctionOLD_CURRENT_USER
Function
EXPAND_SQL_TEXT
ProcedureGET_SQL_HASH
FunctionSQLID_TO_SQLHASH
Function
ANALYZE_DATABASE
ProcedureANALYZE_PART_OBJECT
ProcedureANALYZE_SCHEMA
Procedure
GET_CPU_TIME
FunctionGET_TIME
FunctionGET_TZ_TRANSITIONS
Procedure
WAIT_ON_PENDING_DML
FunctionEXEC_DDL_STATEMENT
ProcedureGET_HASH_VALUE
FunctionIS_BIT_SET
Function
We can see an alternative PL/SQL code suite, with several highly cohesive packages. But there will be some procedures which are genuinely unrelated to anything else. The four procedures in the Unclassified section above are examples. But writing a miscellaneous utils package for these programs is still wrong. There are better options.
- Find a home. It's worth considering whether we already have a package which would fit the new function. Perhaps
WAIT_ON_PENDING_DML()
should have gone inDBMS_TRANSACTION
; perhapsIS_BIT_SET()
properly belongs inUTL_RAW
. - A package of their own. Why not? It may seem extravagant to have a package with a single procedure but consider
DBMS_DG
with its lone procedureINITIATE_FS_FAILOVER()
. The package delivers the usual architectural benefits plus it provides a natural home for related procedures we might discover a need for in the future. - Standalone procedure. Again, why not? We are so conditioned to think of a PL/SQL program as a package that we forget it can be just a Procedure or Function. Some programs are suited to standalone implementation.
So avoiding the Utilities package requires vigilance. Code reviews can help here. Preventing the Utilities package becoming entrenched is crucial: once we have a number of packages dependent on a Utilities package it is pretty hard to get rid of it. And once it becomes a fixture in the code base developers will consider it more acceptable to add procedures to it.