다이나믹 스코프를 가진 언어로 일하지 않는 행운을 가진 사람들을 위해, 그것이 어떻게 작동하는지 조금 알려 드리겠습니다. "RUBELLA"라는 의사 언어가 다음과 같이 작동한다고 가정 해보십시오.
function foo() {
print(x); // not defined locally => uses whatever value `x` has in the calling context
y = "tetanus";
}
function bar() {
x = "measles";
foo();
print(y); // not defined locally, but set by the call to `foo()`
}
bar(); // prints "measles" followed by "tetanus"
즉, 변수는 호출 스택을 자유롭게 위 아래로 전파합니다. 정의 된 모든 변수 foo
는 해당 호출자에게 표시되며 변경 가능 bar
합니다. 그 반대도 마찬가지입니다. 이는 코드 리팩토링에 심각한 영향을 미칩니다. 다음 코드가 있다고 상상해보십시오.
function a() { // defined in file A
x = "qux";
b();
}
function b() { // defined in file B
c();
}
function c() { // defined in file C
print(x);
}
이제에 대한 호출 a()
이 인쇄 qux
됩니다. 그러나 언젠가 b
는 약간 변경해야한다고 결정합니다 . 모든 호출 컨텍스트를 알지 못하지만 (일부는 실제로 코드베이스 외부에있을 수 있음), 그래도 괜찮습니다-변경 사항이 완전히 내부에있을 것 b
입니까? 따라서 다음과 같이 다시 작성하십시오.
function b() {
x = "oops";
c();
}
그리고 로컬 변수를 방금 정의했기 때문에 아무것도 변경하지 않았다고 생각할 수도 있습니다. 그러나 실제로, 당신은 고장났습니다 a
! 이제 보다는 a
인쇄합니다 .oops
qux
이것을 의사 언어 영역에서 다시 가져 오면 이것은 다른 구문으로도 MUMPS의 동작 방식과 정확히 동일합니다.
MUMPS의 최신 ( "현대") 버전에는 소위 NEW
문이 포함되어 있는데,이를 통해 변수가 수신자로부터 발신자에게 누출되는 것을 방지 할 수 있습니다. 우리가했던 경우에 따라서 위의 첫 번째 예에서, NEW y = "tetanus"
에 foo()
, 다음 print(y)
에 bar()
(명시 적으로 다른 것으로 설정하지 않으면 MUMPS에, 모든 이름은 빈 문자열을 가리) 아무것도 출력하지 않을 것이다. 우리가있는 경우 :하지만 수신자에게 발신자로부터 누출 변수를 방지 할 수있는 건 아무것도 없다 function p() { NEW x = 3; q(); print(x); }
, 우리가 알고있는 모두를 위해, q()
돌연변이 수 x
를 명시 적으로 수신되지에도 불구하고, x
매개 변수로는. 이것은 여전히 나쁜 상황이지만, 예전 처럼 나쁘지는 않습니다 .
이러한 위험을 염두에두고 어떻게 MUMPS 또는 다른 언어로 동적 범위를 지정하여 코드를 안전하게 리팩터링 할 수 있습니까?
리팩토링을보다 쉽게하기위한 명백한 모범 사례가 있습니다. 예를 들어, NEW
직접 초기화 하거나 명시적인 매개 변수로 전달 된 것 이외의 함수에서 변수를 사용하지 않고 함수의 호출자로부터 내재적으로 전달 된 매개 변수를 명시 적으로 문서화하는 것과 같습니다 . 그러나 수십 년 전 ~ 10 8 -LOC 코드베이스에서 이들은 종종 가지고 있지 않은 사치입니다.
물론, 어휘 범위를 가진 언어에서 리팩토링에 대한 모든 모범 사례는 동적 범위-쓰기 테스트 등의 언어에도 적용 할 수 있습니다. 그렇다면 리팩토링시 동적 범위 코드의 취약성 증가와 관련된 위험을 어떻게 완화 할 수 있을까요?
동적 언어로 작성된 코드를 탐색하고 리팩터링 하는 방법은 이 질문과 비슷한 제목을 갖지만 전적으로 관련이 없습니다.