하드 코딩 된 값 제거 및 방어 적 설계 vs YAGNI


10

먼저 약간의 배경 지식. Age-> Rate에서 조회를 코딩하고 있습니다. 7 개의 에이지 대괄호가 있으므로 조회 테이블은 7 개의 행이있는 3 개의 열 (From | To | Rate)입니다. 값은 거의 변하지 않습니다 . 3 년 동안 동일하게 유지 된 입 법률 (첫 번째 및 세 번째 열)입니다. 이 테이블을 하드 코딩하지 않고 저장하는 가장 쉬운 방법은 전역 구성 테이블의 데이터베이스에 CSV를 포함하는 단일 텍스트 값이므로 "65,69,0.05,70,74,0.06" 65-69 및 70-74 계층이 저장됩니다). 분석하고 사용하기가 비교적 쉽습니다.

그런 다음이를 구현하려면 새 테이블, 래핑 할 리포지토리, 리포지토리에 대한 데이터 계층 테스트, CSV를 테이블로 확장하는 코드에 대한 단위 테스트 및 조회 자체를 테스트해야한다는 것을 깨달았습니다. 이 모든 작업의 ​​유일한 장점은 조회 테이블을 하드 코딩하지 않는 것입니다.

현재 조회 테이블을 직접 사용하는 사용자 (하드 카피를보고)와 대화 할 때는 "요금이 절대 변하지 않는다"는 의견이 나옵니다. 실제로는 정확하지 않습니다. 요율은 3 년 전에 만 만들어졌고 과거에는 "변경하지 않음"으로 인해 변경되는 습관이있었습니다. 따라서 방어 적으로 프로그래밍하려면 룩업 테이블을 저장해서는 안됩니다. 응용 프로그램.

내가 YAGNI 생각할 때를 제외하고 . 내가 구현하는 기능은 요율이 변경되도록 지정하지 않습니다. 요율이 변경되는 경우에도 유지 보수를 고려할 정도로 요율이 거의 변경되지 않으며, 요율 변경과 업데이트 된 응용 프로그램 사이에 지연이있을 경우이 기능이 실제로 영향을 미칠 정도로 중요하지 않습니다.

조회를 하드 코딩하면 가치가 전혀 없어지지 않기로 결정 했으며이 특정 기능에 대한 접근 방식에 대해 너무 걱정하지 않습니다. 제 질문은 전문가로서 그 결정을 올바르게 정당화 했습니까? 하드 코딩 값은 설계가 좋지 않지만 응용 프로그램에서 값을 제거하는 데 어려움을 겪는 것은 YAGNI 원칙을 위반하는 것 같습니다.

편집 질문을 명확히하기 위해 실제 구현에 대해서는 신경 쓰지 않습니다. 나는 YAGNI를 말함으로써 신속하고 나쁜 일을하고 그것을 정당화 할 수 있는지, 또는 최선의 경우에도 궁극적으로 낮은 혜택을주는보다 방어적이고 노력이 많은 접근법을 취할 수 있을까 걱정하고 있습니다. 전문 프로그래머로서 결함이 있다고 생각되는 디자인을 구현하기로 한 결정은 단순히 비용 / 이익 분석으로 귀결됩니까?

EDIT 모든 해답은 매우 흥미 있었다 나는 이것이 개인의 디자인 선택에 온다 생각하는, 내가 가장 좋은 답변라고 생각하지만 코빈의 @@EZ 하트의 그들은 내가이 질문을 고려하지 않은 것들을 가지고 같이

  • 하드 코딩을 사용하여 'YAGNI를 효율적으로 적용하는 것'과 데이터베이스로 이동하여 '하드 코딩 된 값을 정확하게 제거'하는 잘못된 이분법. 룩업 테이블을 앱 구성에 배치하는 세 번째 옵션이 있는데, 올바른 방법으로 오버 헤드를 발생시키지 않으며 YAGNI의 효율성이 없습니다. 우리는 일반적으로 의사 결정에만 국한되지 않으며 비용 / 혜택 결정으로 이어집니다.
  • 코드 생성은 하드 코딩 된 값을 데이터베이스로 이동하는 오버 헤드를 줄이고 CSV를 테이블로 처리하려는 과도한 엔지니어링 결정을 제거하는 방식입니다. 기본 요구 사항이 조회 방법에 대해 변경되는 경우 생성 된 코드에 장기적인 유지 보수 문제가 추가 될 수도 있습니다. 이것은 비용 / 혜택 분석에만 영향을 미치며, 자동화를 사용할 수 있다면 이와 같은 하드 코딩조차 고려하지 않았을 것입니다.

@Corbin의 대답은 개발 비용에 대한 가정을 변경하기 때문에 올바른 것으로 표시하고 있으며 가까운 시일 내에 무기고에 코드 생성 도구를 추가 할 것입니다.


요율이 변경되고 하드 코딩 된 값인 경우 요율이 변경 될 때 기록 레코드 계산을 엉망으로 만들 수 있습니다 (고객이 말한 내용에 관계없이).
Andy

답변:


6

개발 과정에서 결함을 발견했습니다. 옳은 일을하기가 어려울 때 (테이블 만들기, 리포지토리, 리포 테스트, 평평 테스트 ...) 개발자는 그 주위에 방법을 찾을 것입니다. 일반적으로 잘못된 일을합니다. 이 경우 응용 프로그램 데이터를 응용 프로그램 논리로 취급해야합니다. 하지마 대신 개발 프로세스에 유용한 자동화를 추가하십시오. 우리는 CodeSmith 를 사용 하여 아무도 원하지 않는 지루한 상용구 코드를 생성합니다. 테이블을 만든 후 CodeSmith를 실행하고 DAO, DTO를 생성하고 각각에 대한 단위 테스트를 스텁 아웃합니다.

사용중인 기술에 따라 비슷한 옵션이 있어야합니다. 많은 ORM 도구는 기존 스키마에서 모델을 생성합니다. 레일스 마이그레이션은 모델의 테이블과 반대 방향으로 작동합니다. 동적 언어의 메타 프로그래밍은 특히 상용구 코드를 제거하는 데 강력합니다. 복잡한 다중 계층 응용 프로그램이있는 경우 필요한 모든 것을 생성하려면 조금 더 노력해야하지만 그만한 가치가 있습니다. "와우, 이것은 목에 통증이있다"는 느낌이 올바른 일을하는 것을 막지 않도록하십시오.

아, 그리고 추가 처리 (CSV)가 필요한 형식으로 데이터를 저장하지 마십시오. 주의와 테스트가 필요한 추가 단계 만 추가하면됩니다.


Rails 마이그레이션이 모델에서 테이블을 생성한다고 말하고 싶지는 않습니다 ... Rails 마이그레이션은 테이블의 변경 사항을 설명합니다. 마이그레이션을 실행하면 데이터베이스가 변경됩니다. 테이블 구조와 일치하는 모델 특성은 런타임에 작성됩니다.
kevin cline

이것은 저에게 관심이 있습니다. 초기 노력의 일부를 그 수준으로 자동화하는 것을 고려하지 않았습니다. 그리고 자동화를 통해 시간을 절약하기 위해 CSV를 사용하는 대신 전체 테이블을 설정할 수 있습니다. 내가 걱정하는 것은 생성 된 코드의 장기 유지 관리입니다. 이를 사전에 생성함으로써 조회 수행 방법이 절대 변경되지 않을 것이라는 초기 가정을 세웠습니다. 이것이 가능한 비용인지 여부를 비용 / 혜택의 일부로 고려하여 보일러 플레이트의 비용을 줄입니다. +1
Rebecca Scott

문제는 "고객이 변경하지 않겠다고 말할 때 값을 하드 코딩해야합니까?"였습니다. 그리고 당신의 대답은 "아니오, 사실 당신은 문제에 ORM을 던져야합니다." 동의하지 않습니다. OP가 하드 코딩을 피할 수있는 더 간단한 옵션이 있습니다. 명시 적으로 불필요하게 지정된 것을 지원하기 위해 아키텍처에 큰 추가를하는 것은 비 윤리적입니다. 불행히도 많은 개발자들이 그러한 일을하는 경향이 있습니다. 그리고 나는 "느낌이 '목에 통증이있다'라는 느낌을 갖지 말고 올바른 일을하지 못하게하겠다는 당신의 제안에 100 % 동의하지 않습니다. 그 감정은 중요합니다!
user1172763

10

@ Thorbjørn Ravn Andersen의 답변을 키 오프하고 확장하려면 : 계산 / 조회를 한 곳에 유지하는 것이 좋습니다.

방어 대 YAGNI에 대한 당신의 사고 과정은 일반적인 문제입니다. 이 경우 두 가지 더 알려줄 것을 제안합니다.

첫째, 사용자 요구 사항은 어떻게 제시 되었습니까? 그들은 요금의 편집 가능성을 지정 했습니까? 그렇지 않은 경우 추가 된 복잡성이 청구 할 수있는 것의 일부입니까? (또는 직원 인 경우 다른 작업을하는 데 시간을 할애 할 수 있습니까?) 그렇다면, 계속해서 합리적으로 요청한 내용을 전달하십시오.

둘째, 그리고 아마도 더 중요한 것은, 단지 편집 가능성만으로도 법제화 된 변화에 직면 한 실제 요구 사항을 충족시키지 못할 것입니다. 요율이 변경되는 경우에는 마감일과 일부 전후 처리가있을 수 있습니다. 또한 동일한 인터페이스가 어떤 종류의 백 데이트 클레임 처리를 수행해야하는 경우 실제 날짜가 아닌 항목의 유효 날짜를 기준으로 올바른 요율을 찾아야 할 수 있습니다.

간단히 말해서, 실제 편집 가능한 요구 사항은 상당히 복잡 할 수 있으므로 지적 하지 않은 경우가 아니면 단순 할 때가 더 좋습니다.

행운을 빕니다


1
두 번째 포인트 +1 저는 입법 기관이 앞으로 무엇을할지에 대해 논쟁하지 않습니다.
David Thornley

라이브러리 함수에서 수행하십시오. 한 명의 사용자 만 있으면됩니다. 요구 사항이 변경되는시기와 변경 사항은 한 곳에서 변경할 수 있습니다. (특정 날짜를 기준으로 값을 조회하는 기능을 추가해야 할 수도 있습니다.)
BillThor

가장 완벽한 답변, +1
Andy

7

실제 조회를 라이브러리 함수로 만듭니다. 그런 다음 소스 리포지토리에서 해당 조회를 사용하여 모든 코드를 볼 수 있으므로 요금이 변경 될 때 어떤 프로그램을 업그레이드해야하는지 알 수 있습니다.


조회는 단일 장소 ( PensionRateLookup클래스 와 같은 것)에서만 구현 된 다음 전 세계적으로 사용됩니다. 앱 외부에 저장되어 있거나 하드 코딩되어 있는지 여부에 관계없이 PensionRateLookup클래스 의 구현 만 유지하면됩니다. 내 문제는 룩업 테이블을 하드 코딩하는 것이 허용된다는 결론에 도달하기 위해 YAGNI를 어떻게 사용했는지입니다.
Rebecca Scott

그래도 답변 주셔서 감사합니다. 조회 구현을 한 곳에 유지하는 것은 확실히 좋은 디자인입니다.
Rebecca Scott

YAGNI는 요금이 변경 될 때 새 바이너리를 배송 할 수있는 경우에만 유효합니다. 구성을 변경할 수 없지만 변경할 수있는 경우 현재 텍스트 표현을 기본값으로하여 시작할 때 읽은 구성 값으로 만드십시오.

나는 매주 새로운 버전을 배송하므로 실제로 업데이트를 업데이트하는 것은 문제가되지 않습니다. 클라이언트 구성에 넣는 것은 실제로 새로운 바이너리로 클라이언트 구성을 변경할 수 없으므로 실제로 더 나쁩니다. 내가 볼 수있는 대안은 데이터베이스에 넣는 것이므로 많은 노력이 필요합니다.
Rebecca Scott

그렇다면 무엇이 문제입니까? 요금이 변경되면 코드를 업데이트하고 모든 고객에게 배송 하시겠습니까?

2

질문이 맞는지 알려 드리겠습니다. 기능을 구현하는 두 가지 옵션이 있습니다. 값을 하드 코딩하고 기능을 쉽게 구현할 수 있지만 (하드 코드 부분이 마음에 들지 않지만) 수행 된 많은 작업을 "재실행"하려는 노력이 매우 큽니다. 깔끔한 방식으로 기능을 개발할 수 있습니다. 그 맞습니까?

내 생각에 가장 먼저 오는 것은 "좋은 습관을 아는 것의 가장 중요한 것은 그들이없는 상태에서 나아질 때를 아는 것"입니다.

이 경우 노력이 매우 높으므로 깨끗한 방법으로 할 수 있으며,이 변경으로 인한 부수적 효과가 크고 수익이 적습니다 (설명한 바와 같이, 그렇지 않을 것 같습니다) 변화).

나는 하드 코드 접근 방식을 사용하지만 (향후에 유연하게 준비) 미래 에이 속도가 변경되는 경우 코드 의이 나쁜 디자인 섹션을 모두 리팩토링 할 수있는 기회를 사용하십시오. 따라서 시간과 비용을 정확하게 추정 할 수 있으며 하드 코딩 된 값을 변경하는 비용이 최소화됩니다.

이것은 내 접근 방식 일 것입니다 :)


감사합니다 @Oscar. 그 기술 부분은 데프입니다. 옳은. 그리고 필요할 때만 리팩토링하여 문제에 어떻게 접근 할 것인지에 동의합니다. 당신은 전문가로서 우리는 단지 비용 / 이익에만 근거하여 디자인 원칙을 선택할 수 있고 선택해야한다고 말하는가? 맞는 말이다.
Rebecca Scott

@Ben Scott : 천만에요 :). 예, 제 생각에는 디자인 원칙은 아름답게 보이기보다는 코드 "깨끗함", 유연성, 견고성 등과 같은 이점을 가져 오기 때문에 작성 / 카탈로그되었습니다. 그러나 항상 두 가지 질문이 있습니다. ? 2- 제한 사항 (시간, 기술 등)으로 구현할 수 있습니까? 이것이 일반적으로 저의 설계 원칙을 선택하게합니다. 과도 공학도 나쁘다;) ps : 흥미로운 답변이라고 생각되면 투표하여 다른 사람들도 더 높은 확률로 읽도록하십시오. 감사! :)
JSBach

upvoted ;-)
Rebecca Scott

2

변경 될 때까지 "변경되지 않는"항목입니다. 그것이 바뀔 것이 불가피하지만 그 시간은 조금 멀어 질 수 있습니다.

당신의 정당성은 정확합니다. 현재 고객은 이러한 요율을 쉽게 변경할 수있는 기능을 요구하지 않았습니다. 따라서 YAGNI.

그러나 원하지 않는 것은 요율에 액세스하고 코드베이스 전체에 흩어져있는 결과를 해석하는 코드입니다. 좋은 OO 디자인은 수업료의 내부 표현을 클래스로 캡슐화하고 데이터를 사용하는 데 필요한 하나 또는 두 가지 방법 만 노출시킵니다.

복사 및 붙여 넣기 오류를 방지하기 위해 캡슐화가 필요하거나 내부 표현을 변경해야 할 때 속도를 사용하는 모든 코드에서 리팩토링을 수행해야합니다. 초기 예방 조치를 취할 때 더 복잡한 접근 방식은 간단한 교체 및 더 많은 기능을 갖춘 버전을 대체 할 수 있습니다.

또한 현재 디자인의 한계를 클라이언트에게 알리십시오. 일정을 유지하기 위해 값을 하드 코딩했습니다. 값을 업데이트하려면 코딩 변경이 필요합니다. 이렇게하면 새로운 법률로 인해 보류중인 요율 변경을 알게되면 조회 테이블을 간단히 업데이트하거나 그 시점에서 더 복잡한 변경을 수행하도록 선택할 수 있습니다. 그러나 그 결정을 무릎에 두십시오.


@berin에게 감사드립니다. 질문에 SRP는 언급되지 않았지만 계획에있었습니다. 고객에게 문제의 소유권을 다시 부여하는 것이 좋습니다.
Rebecca Scott

미래에 문제가 생겼을 때 비난을받는 것은 나에게 전문적인 것처럼 보이지 않습니다.
Andy

@ 앤디, 그 중 어떤 부분이 책임을 할당합니까? 고객에게 설계 제한 사항을 제시하면 복잡한 작업의 우선 순위를 정하고 테이블에서 다른 작업을 수행하거나 마감일을 철회하거나 제한적인 설계를 수락 할 수 있습니다. 당신은 그들의 제품에 대한 선택으로 고객에게 힘을 실어주고 있습니다. 고객이 관심을 갖고 선택한 선택의 위험 / 보상을 인식하게하면 프로젝트가 더 순조롭게 진행됩니다.
Berin Loritsch

@BerinLoritsch 그러나이 특정 설계 결정은 "이 배관 파이프 퍼티를 사용하여이 새는 파이프를 막을 수 있습니다."라는 말은 표준 이하의 부품을 사용하는 것과 비슷합니다. 요금이 변경됩니다. 그것은 주어진 것이며 전문가가 그것을 허용하지 않는 시스템을 만드는 것은 무책임합니다. 그리고 비용 절감은 프로젝트 비용의 큰 계획에서 무시할 수 있습니다. 데이터를 테이블에 넣으십시오. 조회 데이터를 가져 오는 코드는 약간 다르므로 사용할 속도를 알아내는 논리는 어느 쪽이든 동일합니다. 유일한 다른 결정은 이후에 기록 데이터를 처리하는 방법입니다.
Andy

요율 변경은 일반적으로 요율을 관련 레코드로 복사하여 처리됩니다. 이 시점에서 관리자 화면이 필요하지 않으며 시스템은 요율이 변경 될 때 처리 할 수 ​​있으며이를 변경하는 간단한 스크립트가됩니다. 이 중 어느 것도 몇 시간을 초과해서는 안되지만 내년 퍼티가 실패하면 지하실이 범람하는 것을 막을 것입니다.
Andy

2

차이를 분할하고 속도 데이터를 구성 설정에 넣습니다. 이미 가지고있는 CSV 형식을 사용할 수 있으며 불필요한 데이터베이스 오버 헤드를 피할 수 있으며, 변경이 필요한 경우 고객이 다시 컴파일 / 재설치하거나 엉망하지 않고 변경할 수 있어야합니다. 데이터베이스에서-구성 파일을 편집하기 만하면됩니다.

일반적으로 두 가지 극단 (YAGNI 대 하드 코딩 동적 데이터 위반) 사이의 선택을 볼 때 가장 좋은 대답은 중간에 있습니다. 거짓 이분법에주의하십시오.

이것은 모든 구성이 파일에 있다고 가정합니다. 레지스트리와 같이 어딘가 어려운 경우이 조언을 무시해야합니다. :)


구성 설정에서 사용하는 것을 고려했지만 CSV 문자열을 편집하는 한 사용자가 기술적이지 않기 때문에 따로 두었습니다. 따라서 N 사용자의 구성을 업데이트하는 사람이 될 것입니다 (모든 IT 지원을 노력과 관련하여 한 곳에서 관리 할 수있는 데이터베이스로 가져 오기 위해 선행 작업을 수행하는 것이 더 쉬울 것입니다. 그것이 고려되지 않은 경우 (사용자가 개별 구성을 관리 할 수있는 경우)이 문제가 없을 것이라고 생각합니다. 아주 좋은 지적입니다. 감사합니다.
Rebecca Scott

이것을 중앙 집중식 논리의 다른 제안과 결합하면 큰 대답입니다. 구성을 통해 변경 될 수있는 방식으로 배치하는 대신 실제로 하드 코어 조회를 수행하는 것은 순수한 악입니다. 다른 개발자가 나올 때마다 그들은 당신을 미워할 것입니다. 한 개발 직원조차도 버스에 치면 어떻게 될지 고려해야하며 다음 개발자가 정식 소프트웨어 릴리스없이 값을 쉽게 변경할 수 있도록해야합니다. 클라이언트를 미워하고 다른 모든 개발자를 미워하는 경우에만 하드 코어해야합니다. 기본적으로 절대로.
simbo1905

2

이 테이블을 하드 코딩하지 않고 저장하는 가장 쉬운 방법은 전역 구성 테이블의 데이터베이스에 CSV를 포함하는 단일 텍스트 값이므로 "65,69,0.05,70,74,0.06" 65-69 및 70-74 계층이 저장됩니다.

방금 DB 테이블을 만들었습니다. (전체 테이블을 하나의 파일로 저장하려는 생각이 있다면 화났습니까?)

이 테이블에는 NOT 3 연령 및 비율 필드가 필요합니다. 다음 행에는 더 높은 값이 포함됩니다! 당신은 그것을 모른 채 비정규 화하고 있습니다!

다음은 67 세인 사람의 요금을받는 Sql입니다.

Select * from RateTable where Age in (Select max(age) from RateTable where age <=67) 

유지 관리 화면이 범위를 벗어나므로 귀찮게하지 마십시오. 나중에 요청하면 변경 요청을 발행하여 수행하십시오.

편집 : 다른 사람들이 말했듯이 전체 Rate 구조가 변경 되는 경우 코드를 중앙 집중식으로 가져옵니다 .


@Morons 님, 답변 주셔서 감사합니다. 테이블에는 실제로 3 개의 열이 필요합니다. 연령대, 최소 연령에서 최대 연령 까지 의 단일 비율입니다 (65-69 세는 5 %입니다). 그리고 제한된 목적을 위해 소량의 데이터 만 저장하고 있으므로 구조를 가정하고 전체 전용 테이블 대신 CSV를 사용하는 데 어떤 문제가 있습니까? 아마도 행 구분 기호를 추가하고 행별로 나누고 열을 나누고 열을 필수 필드로 가져옵니다. 이것은 항상 쓰여진 것보다 훨씬 더 많이 읽히므로 전체 테이블에 대해 너무 걱정하지 않아도됩니다.
Rebecca Scott

다음 행은 범위의 상한값을 포함합니다. 이것은 데이터의 복제입니다. <69와> 7은 같은 것입니다. 두 값을 모두 갖는 유일한 이유는 범위에 구멍이있을 수 있기 때문입니다. ... 테이블이 더 쉽고 디자인이 더 좋기 때문에 테이블을 사용하려고합니다. csv를 테이블에 저장하면 시간이나 노력을 절약 할 수 있다고 생각하는 이유를 이해하지 못합니다.이 문자열을 얻으려면 여전히 DB 호출이 필요하며 구문 분석해야합니다. 위에서 보여 드린 것처럼 단일 DB 호출로 요금을 얻을 수 있습니다.
Morons

아 맞다. 나는 테이블 자체를 소스 자료와 유사하게 유지하고 있었고 ... 나는 당신에게 슬픔을 준 슬픔이 있었기 때문에 나이가 대답의 상한이라는 것을 놓쳤다.
Rebecca Scott

1
"당신은 그것을 몰라도 모독 중입니다!" -처음에 나는 이것이 오타라고 생각하고 당신이 '비정규 화'를 의미한다고 생각했지만, 그것에 대해 더 많이 생각할수록 당신은 어느 쪽이든 옳을 것 같았습니다 :)
EZ Hart

@ez 하트 LOL true.
Rebecca Scott

1

나는 대부분의 답변에 동의합니다. 또한 나머지 응용 프로그램과의 일관성이 중요하다는 점도 덧붙입니다. 이것이 코드에서 하드 코딩 된 값을 가진 유일한 장소라면 아마도 관리자를 놀라게 할 것입니다. 크고 안정적인 코드 기반 인 경우 특히 그렇습니다. 그것이 당신에 의해 유지되는 작은 프로그램이라면 결정은 덜 중요합니다.

잘 알려진 애자일 / OOP 사람 (데이브 토마스 나 켄트 벡 또는 다른 사람)이 코드 복제에 대한 경험 법칙이 두 번, 두 번이라고 말하는 먼 기억이 있습니다. 당신은 인생에서 두 번만 쓸 수 있습니다. 하지만 세번째는 ...

YAGNI에 의문을 제기하고 있기 때문에 그 질문을 정확하게 다루지는 않지만 민첩한 규칙의 일반적인 유연성에 대해 생각합니다. 민첩성의 요점은 상황에 적응하고 앞으로 나아가는 것입니다.


@Dave에게 감사합니다. 도움이됩니다. 나는 처음부터 유일한 관리자이지만, 비교적 크고 안정적인 코드베이스 (수천 개의 파일, 100 개가 넘는 테이블 등)이며 여전히 놀랍고 놀랍습니다. 일관성은 확실히 내 목표 중 하나입니다.
Rebecca Scott

0

함수의 하드 코드.

  • 값이 변경되면 고객에게 다시 청구 할 수 있습니다
  • 값이 변경되면 테이블 형식이 변경 될 가능성이 있으며 CSV를 수행하면 시간이 낭비됩니다
  • 현재 계약으로 예산을 책정 할 가능성이 높고 구현이 쉬움
  • 업데이트가 필요할 때 쉽게 찾을 수 있습니다

이 하위 표준 값을 설치하여 1 년 안에 가장 확실하게 중단되면 비즈니스를 반복 할 수 있습니다. 그렇기 때문에 그늘이 들립니다.
Andy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.