Introduction We focus on recommended Good Programming Practices (GPP) that should be followed when developing SAS Macros and are meant to compliment the PHUSE Guidance on Good Programming Practice from Good Programming Practice in Health and Life Sciences and summarised in the PHUSE GPP Summary. The macro capability is offered in many computer programming languages. A SAS macro implements code generation, based on dynamic, data-driven, run-time conditions. The macro language variables, functions, and statements are interpreted by the macro processor during compilation. The text that is generated (resolved) by the macro language can then be interpreted as SAS code and run by the SAS compiler. A SAS macro is used where the underlying program is well understood, and certain parts need to be modified based on changes in run-time conditions. |
Importance of Good Programming Practices for Macros Following Good Programming Practices help to enhance the quality of a macro. An effective macro is one that is simple, readable and adaptable. If the macro is poorly designed, does not have a logical flow, is not adaptable, or not readable, it defeats the very purpose of being a macro. Because a macro is composed of SAS code and generates resolved SAS code based on the macro parameter settings, Good Programming Practice (GPP) for coding a SAS program applies equally to coding the SAS code within a macro and the SAS code that the macro generates, as discussed in PHUSE GPP and summarised in PHUSE GPP Summary. GPP for macro coding extends these concepts to the SAS macro language and the unique capabilities it brings to the SAS programming environment. Macros generally have a long use life and are often updated by different programmers who adopt them in their work. The scope of a macro may initially be small and grow over time as multiple programmers make updates to the macro. If GPP are not followed the programs often become overly complex, hard to maintain and hard to use. A few overarching guiding principles follow.
|
Gathering User Requirements Like any other program, a macro is built based on the requirements that triggered its need. Understanding the requirement clearly is the key to building a strong base for a macro. As a programmer, when you start to write a macro, you will straight away head for the %macro statement. This is not necessarily the best approach. The starting point is summarising the requirements. The scope and requirements of a macro must be thoroughly documented in order to facilitate easy execution of the macro, ensure the correct output is generated and assist the developers in understanding the reasoning and methodology so they can accurately develop or modify the program. It is extremely important to gather the user requirements accurately and completely, and document them clearly and concisely. Documenting clear requirements will reduce the chance of ambiguity and misunderstanding in the development stage of the program and will reduce rework. It’s important to identify and involve the correct users in the requirement phase, especially when much functionality is needed. The developer must collaborate closely with the users and communicate possible coding or technical challenges. User requirements are often collected in an indexed manner as described in Appendix I. It is helpful, in consolidating the requirements input, to store the requirements documentation in a shared space that all involved users and developers have write access to. Some of the user requirements may be copied to the program specification document and can also be used when drafting user-guides. |
Architecture/Design of a Macro Sharing a standard macro template that models a consistent layout and includes standard programming code for routine functions will help maintain consistency in design of all the macros in an organisation or department. See a sample in Appendix II.
%put ---------------------------------------------------------------; %put --- Start of %upcase (&sysmacroname) macro ; %put --- ; %put --- Macro parameter values ; %put --- input_dataset = &input_dataset ; %put --- output_dataset = &output_dataset ; %put ---------------------------------------------------------------;
|