SAS Kiểm tra tham số đầu vào trong Macro

Tham Khảo: https://support.sas.com/resources/papers/proceedings/proceedings/sugi30/015-30.pdf

VẤN ĐỀ
(Lược bỏ đoạn đầu)
Khi nói đến nó, việc viết các macro sử dụng các tham số có thể có rất nhiều vấn đề. 
Một số macro có một vài tham số. Một số macro có thể có rất nhiều tham số. Các tham số có thể được thêm vào. Các thông số có thể được gỡ bỏ. Các tham số có thể được thay đổi. Điểm mấu chốt khi phát triển macro cho bất kỳ việc sử dụng rộng rãi hệ thống là: 
các tham số cần được kiểm tra.

Các tham số macro cần được kiểm tra trước khi bắt đầu bất kỳ quá trình xử lý thực tế nào
Các tham số cần được chú thích cụ thể. 
Tuy nhiên kể cả khi chú thích, người dùng có thể nhập một số giá trị không chính xác, vì vậy tham số cần kiểm tra.

Câu trả lời rõ ràng là cẩn kiểm tra từng tham số trong macro trước khi bắt đầu quá trình xử lý.
Điều này cho phép người dùng nhận phản hồi tức thì nếu có vấn đề, cũng như đảm bảo rằng sẽ không có kết quả nào được tạo dựa trên các giá trị tham số không chính xác.

AN ANSWER
The following is an example of a simple way to check parameters in a macro.

```sass
%macro blah(Protocol=,
	Default =5,
	Test = );
	%if (%substr(&Protocol,1,1) ^= A) %then %do ;
	%put ERROR: Invalid protocol number!;
	endsas ;
	%end ;
	%if (0 < &Default or &Default > 10 ) %then %do ;
	%put !!! Default value is incorrect !!! ;
	endsas ;
	%end ;
%mend;
```
MỘT SỐ VẤN ĐỀ
Có thể bạn đã thấy một số vấn đề với giải pháp này. 
Một vấn đề dễ thấy là thông báo lỗi không nhất quán.
Điều này dễ thấy trong ví dụ này, nhưng khó tìm hơn khi nhiều người đồng thời cùng phát triển nhiều macro, và sau đó kết hợp chúng thành một hệ thống.
Không phải là một lỗi nghiêm trọng, nhưng gây khó chịu cho người dùng.

Một vấn đề lớn hơn đối với người dùng là họ phải nhớ tất cả các tham số khi sử dụng macro.
Documentation and training là những câu trả lời tuyệt vời cho những câu hỏi này, 
nhưng đôi khi người dùng không có sẵn cái này hay cái khác.


Có lẽ vấn đề lớn nhất và khó theo dõi nhất là nếu một tham số thay đổi từ character thành một giá trị number, hoặc từ một Boolean yes / no thành một số thực.
the users need new training and documentation for this.

TIÊU CHUẨN
Một trong những cách dễ nhất để giáo dục các nhà phát triển và người dùng về ý nghĩa của một biến là có một số tiêu chuẩn cho các tên biến.

Với sự ra đời của phiên bản 7 của SAS, độ dài tên biến vĩ mô đã được mở rộng thành 32 ký tự.
Một số người nghĩ rằng điều này chỉ thêm nhiều hơn vào tác vụ đánh máy, nhưng nó cũng cho phép các tên biến tiêu chuẩn hơn.

Trong C, Visual Basic và các ngôn ngữ khác, một tiêu chuẩn đã xuất hiện để đặt tên biến. 
Nó được gọi là ký hiệu Hungary.

Nó chỉ đơn giản là thêm một tiền tố vào một tên biến để xác định loại hình biến đổi của loại nào.
Ví dụ:

```sass
is = YES/NO
chr = Character
num = Numeric
```

Bằng cách kết hợp quy ước đặt tên tiêu chuẩn cho các tham số macro của bạn, 
cả người dùng và nhà phát triển sẽ hiểu rõ hơn về những gì được mong đợi của từng tham số.
Sau đây là một ví dụ đơn giản.

```sass
%macro combine(chrProtocolName A-123,
	　 isDummyRun =no,
	　 chrSubjectIDRange =,
	　 numSubjects =,
	　 isWithinCenter =no,
	　 numCenters =,
	　 numCenterSubjects =,
	　 numTreatments =,
	　 isStratified =no,
	　 numList =1);
 ```

Đây không phải là toàn bộ giải pháp. 
Điều này chỉ giúp bạn thấy loại giá trị nào sẽ được truyền qua từng tham số. Vấn đề lớn hơn là làm thế nào để bạn, với tư cách là một nhà phát triển, kiểm tra các tham số này theo cách hiệu quả và không trở nên nặng nề. 

AN OPTION AND A MACRO VARIABLE
Triết lý của tôi về lập trình SAS là: Hãy để máy tính và ngôn ngữ làm công việc lặp đi lặp lại.
Hệ thống SAS cung cấp tùy chọn và biến macro tự động (tương ứng với PARMBUFF và &SYSPBUFF) có thể giúp bạn kiểm tra các tham số macro.
Sự kết hợp này cho phép thu thập các tham số macro được truyền cho một macro.

Giả sử rằng bạn có định nghĩa macro dưới đây với tùy chọn PARMBUFF được thêm vào:

```sql
%macro blah(chrParm =,
	numDefault=100,
	numParm = ) /parmbuff;
%mend;

/*If it is called with these parameters,*/
%blah(chrParm = testing,
	numParm = 3.1.1579)
	
/*sau đó biến macro & SYSPBUFF sẽ giải quyết như sau:*/

%put syspbuff=&syspbuff ;
/*syspbuff=(chrParm=testing, numParm=3.1.1579) */

```

Bạn có thể thấy rằng SAS cung cấp một chuỗi macro chứa bất kỳ tham số nào được truyền cho macro.
Lưu ý rằng mọi giá trị mặc định không thay đổi sẽ không được bao gồm trong chuỗi.
Hệ thống SAS đang cung cấp cho bạn tất cả thông tin mà bạn cần để dễ dàng kết hợp một bộ kiểm tra tham số tiêu chuẩn trong tất cả các macro đang được phát triển.

GIẢI PHÁP
Đặt tất cả các tiến trình cùng nhau, bạn có thể tạo một macro kiểm tra tham số duy nhất mà không yêu cầu thêm nỗ lực nào từ phía bạn.
Bằng cách áp dụng các tiền tố tiêu chuẩn cho các tham số và tận dụng tính năng được cung cấp bởi hệ thống SAS, một macro đơn giản có thể được viết để tự động hóa việc kiểm tra các tham số macro.
Sau đây là một macro kiểm tra tham số (check_parameter) có thể dễ dàng được mở rộng khi các loại tham số tiêu chuẩn hơn được phát triển.
Mỗi loại tham số của các loại khác sẽ yêu cầu một macro kiểm tra lỗi tiêu chuẩn và mỗi trong số chúng sẽ được gọi trong macro này.
Các tham số macro là danh sách tham số được cung cấp bởi sự phân giải của biến macro &SYSPBUFF và tên của macro có tham số đang được kiểm tra.
Điều này được sử dụng để cung cấp thông báo trong log, có thể hữu ích cho người dùng khi debug.

```sql

%macro check_parameters(lstParameters, chrMacroName);
	%let errorz = 0;
	%let _done = 0;
	%let _count = 1;

/*The macro reads in a string through the lstParameters parameter. A ‘$$=$$’ is added to show the end of the list of parameters. This is a simple way to know when you are done parsing through a string (or macro variable). 
The two characters removed from the length are the parentheses that enclose the list of parameters.
Macro đọc trong một chuỗi thông qua tham số lstParameter.
Một ‘$$ = $$, được thêm vào để hiển thị phần cuối của danh sách các tham số.
Đây là một cách đơn giản để biết khi nào bạn hoàn thành phân tích cú pháp thông qua một chuỗi (hoặc biến macro).
Hai ký tự được loại bỏ khỏi độ dài là dấu ngoặc đơn kèm theo danh sách các tham số.*/

	%let length = %eval(%sysfunc(length(&lstParameters)) -2) ;
	%let parameters = %sysfunc(substr(&lstParameters, 2, &length))%str(, $$=$$) ;

/*The string is parsed through to get the name-value combinations for parameter = value.
Chuỗi được phân tích cú pháp thông qua để có được các kết hợp tên-giá trị cho tham số = value.*/

	%do %until(&_done) ;
		%let parm_name = %scan(%nrquote(&parameters), &_count, %nrquote(,)) ;
		%let parm_value = %scan(&parm_name, 1, %str(=)) ;
		%if (&parm_value = %nrquote($$)) %then %let _done = 1 ;

/*This section of the code checks the parameter prefix to see if the parameter is of a certain type. Based on the prefix, the parameter is checked by the appropriate type checking macro.
Phần này của mã kiểm tra tiền tố tham số để xem tham số có thuộc loại nhất định không. Dựa trên tiền tố, tham số được kiểm tra bằng macro kiểm tra loại thích hợp.*/

	%else %do ;
		%if %substr(&parm_ value, 1, 2) = is %then
			%yesno_parameter(&parm_value) ;
		%else %if %substr(&parm_ value, 1, 3) = chr %then
			%char_parameter(&parm_value) ;
		%end ;
		%** Increment the parameter count. ;
		%let _count = %eval(&_count + 1) ;
	%end ;
 
/*Each parameter checking macro will return an error message about that “type” of macro parameter. At the end of all
of the checking, a single standard message is used inform you that there is a problem with one or more parameters.
At this point you know all of the parameters that have invalid values, as well as the macro that used them.
Mỗi macro kiểm tra tham số sẽ trả về một thông báo lỗi về kiểu tham số macro đó.
Khi kết thúc tất cả các kiểm tra, một thông điệp tiêu chuẩn duy nhất được sử dụng thông báo cho bạn rằng có một vấn đề với một hoặc nhiều tham số.
Tại thời điểm này, bạn biết tất cả các tham số có giá trị không hợp lệ, cũng như macro đã sử dụng chúng.*/

	%if (&errorz > 0) %then %do ;
		%put ----- There were errors found in parameters defined for
				&chrMacroName.. The application will stop. ;
	%end ;
%mend; 
```

So in the end, you have a self-documented macro call that is not much more verbose then old cryptic eight character or less parameter names.
Vì vậy, cuối cùng, bạn có một cuộc gọi macro tự ghi lại mà không dài dòng hơn nhiều so với tên ký tự tám hoặc mật mã ít hơn.

```sql
%macro combine(chrProtocolName =Test,
				isDummyRun =no,
				chrSubjectIDRange =,
				numTreatments =,
				allocation_of_treatments =,
				isStratified =no,
				numList =1) / parmbuff;
/*The only addition needed to check all parameters with standard prefixes is this simple macro.
Bổ sung duy nhất cần thiết để kiểm tra tất cả các tham số với tiền tố tiêu chuẩn là macro đơn giản này.*/
%*** All parameter checking here... ;
	%check_parameters(&syspbuff, Combine);
%mend ;
```
The only effort on the developer’s part is the second parameter that identified the macro whose parameters need to be checked. 
Nỗ lực duy nhất trên phần nhà phát triển là tham số thứ hai xác định macro có tham số cần kiểm tra.

Adding this call to all new macros will allow for consistent parameter checks to be run on any new macro, regardless of the user or developer.
Thêm cuộc gọi này vào tất cả các macro mới sẽ cho phép kiểm tra tham số nhất quán được chạy trên bất kỳ macro mới nào, bất kể người dùng hoặc nhà phát triển.

KẾT LUẬN
Bằng cách phát triển và sử dụng các quy ước đặt tên tiêu chuẩn cho các tham số macro, bạn hiểu rõ hơn về hệ thống thông qua các loại dữ liệu dự kiến trong mỗi cuộc gọi macro. 
Kết hợp các thành phần tiêu chuẩn của SAS hệ thống, bao gồm PARMBUFF và & SYSPBUFF, sẽ cho phép bạn dễ dàng thêm kiểm tra tiêu chuẩn vào các tham số cho tất cả các macro mới mà bạn đang viết.