널이 악한 경우 값이 의미가 없을 때 사용해야하는 것은 무엇입니까?


26

이것은 반복해서 반복되는 규칙 중 하나이며 저를 당혹스럽게 만듭니다.

널 (null)은 사악하므로 가능할 때마다 피해야합니다 .

그러나 내 순진함에서 비명을 지르는 경우가 있습니다. 때로는 가치가 없을 수도 있습니다!

내가 지금하고있는이 안티 패턴 타기 끔찍한 코드 에서 나온 예제에 대해 물어보십시오 . 이것은 핵심적으로 멀티 플레이어 웹 턴 기반 게임으로 두 플레이어의 턴이 동시에 진행됩니다 (포켓몬과 마찬가지로 체스와 반대).

각 차례가 지나면 서버는 업데이트 목록을 클라이언트 쪽 JS 코드로 브로드 캐스트합니다. 업데이트 클래스 :

public class GameUpdate
{
    public Player player;
    // other stuff
}

이 클래스는 JSON으로 직렬화되어 연결된 플레이어로 전송됩니다.

대부분의 업데이트에는 당연히 플레이어가 연결되어 있습니다. 결국 어떤 플레이어가이 턴을했는지 알아야합니다. 그러나 일부 업데이트에는 플레이어와 의미있게 연결된 플레이어가 없을 수 있습니다. 예 : 액션이없는 회전 제한이 초과되어 게임이 강제로 연결되었습니다. 그러한 업데이트의 경우 플레이어가 null을 갖는 것이 의미가 있다고 생각합니다.

물론 상속을 활용하여이 코드를 "수정"할 수 있습니다.

public class GameUpdate
{
    // stuff
}

public class GamePlayerUpdate : GameUpdate
{
    public Player player;
    // other stuff
}

그러나 나는 두 가지 이유로 이것이 어떻게 개선되는지 알지 못합니다.

  • JS 코드는 이제 Player가없는 객체를 정의 된 속성으로받습니다. 두 경우 모두 값이 있는지 또는 없는지 확인해야하기 때문에 null 인 경우와 같습니다.
  • 또 다른 nullable 필드가 GameUpdate 클래스에 추가되면 다중 상속을 사용 하여이 desing을 계속할 수 있어야하지만 MI는 자체적으로 (보다 숙련 된 프로그래머에 따르면) 악의적이며 더 중요한 것은 C #이 아닙니다. 사용하지 못하도록하십시오.

나는이 코드 의이 부분이 경험이 많고 훌륭한 프로그래머가 공포에서 비명을 지르는 매우 많은 것 중 하나라는 것을 알고 있습니다. 동시에 나는이 장소 에서이 널이 어떻게 상처를 입히고 어떻게 해야하는지 알 수 없습니다.

이 문제를 설명해 주시겠습니까?


2
이 질문이 JavaScript에만 해당됩니까? 많은 언어가이 목적을 위해 선택적인 유형을 가지고 있지만 js에 하나가 있는지 (하나를 만들 수는 있지만) json과 함께 작동하는지 여부는 알 수 없습니다 (여전히 코드 전체에서 null null 검사의 일부이지만
Richard Tingle

9
그 규칙은 거짓입니다. 나는 누군가가 그 개념을 구독한다는 것에 약간 놀랐습니다. 경우에 따라 null 대신 사용할 수있는 좋은 대안이 있습니다. null은 결 측값을 나타내는 데 정말 좋습니다. 자신의 합리적인 판단을 신뢰하지 못하게하는 임의의 인터넷 규칙을 허용하지 마십시오.
usr

1
@usr-전적으로 동의합니다. 널은 당신의 친구입니다. IMHO, 결 측값을 나타내는 더 명확한 방법은 없습니다. 버그를 찾는 데 도움이되고, 오류 조건을 처리하는 데 도움이되고, 용서를 구하는 데 도움이됩니다 (시도 / 캐치). 싫어하는 것은 무엇입니까?!
스쿠버 스티브

4
소프트웨어 설계의 첫 번째 규칙 중 하나는 "항상 null 확인"입니다. 이것이 문제인 이유는 나에게 흔들리는 마음입니다.
MattE

1
@MattE-물론입니다. Null이 기본 도구 상자에 포함되어있는 것이 좋은 경우 설계 패턴을 설계하는 이유는 무엇입니까? Graham이 제안한 IMHO는 저를 과도하게 설계했습니다.
스쿠버 스티브

답변:


20

null보다 많은 것들이 반환하는 것이 좋습니다.

  • 빈 문자열 ( "")
  • 빈 컬렉션
  • "선택적"또는 "아마도"모나드
  • 조용히 아무것도하지 않는 기능
  • 조용히 아무것도하지 않는 메소드로 가득 찬 객체
  • 질문의 잘못된 전제를 거부하는 의미있는 값
    (처음에는 null을 고려한 이유)

트릭은 언제 이렇게해야하는지 깨닫고 있습니다. Null은 실제로 얼굴을 날리는 데 능숙하지만 확인하지 않고 얼굴을 가리킬 때만 가능합니다. 이유를 설명하는 데 좋지 않습니다.

폭파 할 필요가없고 null을 확인하지 않으려면 다음 대안 중 하나를 사용하십시오. 컬렉션에 0 또는 1 개의 요소 만있는 경우 컬렉션을 반환하는 것이 이상하게 보일 수 있지만 누락 된 값을 자동으로 처리하는 것이 좋습니다.

Monads는 멋지게 들리지만 여기서 그들이하는 일은 컬렉션의 유효한 크기가 0과 1임을 분명히하는 것입니다.

이들 중 어느 것도 null보다 의도를 명확하게하는 더 나은 작업을 수행합니다. 그것이 가장 중요한 차이점입니다.

단순히 예외를 던지기보다는 왜 돌아 오는지 이해하는 데 도움이 될 수 있습니다. 예외는 본질적으로 가정을 거부하는 방법입니다 (유일한 방법은 아님). 두 선이 교차하는 지점을 요청하면 두 선이 교차한다고 가정합니다. 그들은 평행 할 수 있습니다. "병렬 라인"예외를 던져야합니까? 글쎄, 그러나 지금은 예외를 다른 곳에서 처리하거나 시스템을 중지시켜야합니다.

당신이있는 곳에 머무르고 싶다면 그 가정의 거부를 결과 나 거부를 표현할 수있는 일종의 가치로 구울 수 있습니다. 그렇게 이상하지 않습니다. 우리는 항상 대수학 에서합니다. 비결은 그 가치를 의미있게 만들어서 무슨 일이 있었는지 이해할 수 있도록하는 것입니다.

리턴 된 값이 결과 및 거부를 표시 할 수 있으면 둘 다 처리 할 수있는 코드로 전송해야합니다. 다형성은 여기서 사용하기에 정말 강력합니다. 단순히 검사를 위해 null 검사를 교환하지 않고 isPresent()두 경우 모두 잘 작동하는 코드를 작성할 수 있습니다. 빈 값을 기본값으로 바꾸거나 자동으로 아무 것도 수행하지 않습니다.

null의 문제점은 너무 많은 것을 의미 할 수 있다는 것입니다. 따라서 정보가 파괴됩니다.


내가 가장 좋아하는 null 생각 실험에서 나는 컨베이어 벨트에서 컬러 전구를 집어 들고 소켓에 나사로 조이고 전원 을 켜서 컬러 라이트를 사용하여 인코딩 된 메시지를 시그널링 하는 복잡한 Rube Goldbergian 머신 을 상상해 보라고 요청합니다 . 신호는 컨베이어 벨트에 배치 된 다른 색상의 전구에 의해 제어됩니다.

메시지 사이에 마커가 있어야한다는 RFC3.14159를 준수하여이 값 비싼 항목을 만들라는 요청을 받았습니다. 마커는 전혀 빛이 없어야합니다. 정확히 한 펄스 동안 지속되어야합니다. 단색 빛이 정상적으로 비추는 시간과 동일합니다.

contraption이 경보를 설정하고 소켓에 넣을 전구를 찾지 못하면 정지하기 때문에 메시지 사이에 공백을 둘 수는 없습니다.

이 프로젝트에 익숙한 모든 사람은 기계를 만지거나 제어 코드를 만지더라도 떨립니다. 변경하기 쉽지 않습니다. 당신은 무엇을합니까? 글쎄, 당신은 잠수하고 일을 시작할 수 있습니다. 어쩌면이 끔찍한 디자인을 업데이트하십시오. 예, 훨씬 더 나아질 수 있습니다. 또는 청소부와 대화하고 타 버린 전구를 수집 할 수 있습니다.

이것이 다형성 솔루션입니다. 시스템은 변경된 내용을 알 필요조차 없습니다.


그것을 뽑아 낼 수 있다면 정말 좋습니다. 가정에 대한 의미있는 거부를 값으로 인코딩하면 질문을 강제로 변경할 필요가 없습니다.

내가 사과 1 개를 주면 얼마나 많은 사과를 줘야합니까? -1. 어제부터 사과 2 개를 빚 졌기 때문입니다. 여기서 "당신은 나에게 빚을 질 것이다"라는 질문의 가정은 음수로 기각됩니다. 질문이 잘못되었지만 의미있는 정보가이 답변에 인코딩됩니다. 의미있는 방식으로 거부함으로써 질문은 바뀌지 않습니다.

그러나 때때로 질문을 바꾸는 것이 실제로가는 길입니다. 여전히 유용하지만 가정이 더 신뢰할 수 있다고 가정하면 그렇게하는 것을 고려하십시오.

문제는 일반적으로 플레이어가 업데이트를 제공한다는 것입니다. 그러나 플레이어 1 또는 플레이어 2에서 제공되지 않는 업데이트가 필요하다는 것을 발견했습니다. 시간이 만료되었다는 업데이트가 필요합니다. 어느 선수도 이것을 말하지 않으므로 어떻게해야합니까? 플레이어 널을 떠나는 것은 너무 유혹적인 것 같습니다. 그러나 그것은 정보를 파괴합니다. 블랙홀에서 지식을 인코딩하려고합니다.

선수 필드는 누가 방금 이사했는지 알려주지 않습니다. 당신은 그렇게 생각하지만이 문제는 거짓말임을 증명합니다. 플레이어 필드는 업데이트의 출처를 알려줍니다. 시간이 만료 된 업데이트가 게임 시계에서 제공됩니다. 내 추천은 시계가 가치있는 신용을주고 player필드 이름 을 다음과 같이 변경하는 것 source입니다.

이렇게하면 서버가 종료되고 게임을 일시 중단해야하는 경우 상황을보고하고 업데이트 소스로 표시되는 업데이트를 보낼 수 있습니다.

이것은 결코 무언가를 버려서는 안된다는 것을 의미합니까? 아니요. 그러나 잘 알려진 단일 기본값을 의미하는 것은 없습니다 . 과도하게 사용하기 쉬운 것은 없습니다 . 사용시주의하십시오. 아무것도 선호하는 것을 포용하는 사고의 학교가 있습니다 . 이것을 컨벤션 오버 컨벤션 이라고 합니다 .

나는 그것을 좋아하지만 대회가 어떤 식 으로든 명확하게 전달 될 때만. 초보자를 노리는 방법이되어서는 안됩니다. 그러나 그것을 사용하더라도, null은 여전히 ​​최선의 방법은 아닙니다. 널은 위험한 것이 아니다 . 널 (Null)은 사용할 때까지 바로 사용할 수있는 것처럼 가장 한 다음 우주에 구멍을 날려 버립니다 (의미 론적 모델이 깨짐). 우주에 구멍을 뚫지 않는 한 왜 이런 행동을해야합니까? 다른 것을 사용하십시오.


9
"0 또는 1 개의 요소 만있는 경우 컬렉션을 반환합니다"-죄송 합니다만, 그렇지 않다고 생각합니다. ((1) 내 POV에서이 작업을 수행하면 (a) 불필요한 유효하지 않은 상태가 클래스에 추가됩니다 (b). 컬렉션이 최대 1 개의 요소 (c)를 가져야 만 어쨌든 문제를 해결하지 못하는 것 같습니다. 어쨌든 컬렉션에 액세스하기 전에 유일한 요소가 포함되어 있는지 확인하면 예외가 발생합니까?
gaazkam

2
@gaazkam 참조? 나는 사람들에게 버그가 있다고 말했습니다. 그러나 빈 문자열을 사용할 때마다 정확히 수행 한 것입니다.
candied_orange

16
빈 문자열 또는 집합으로 유효한 값이 있으면 어떻게됩니까?
Blrfl

5
어쨌든 @gaazkam, 컬렉션에 항목이 있는지 명시 적으로 확인하지 않습니다. 빈 목록을 반복 (또는 매핑)하는 것은 아무런 효과가없는 안전한 동작입니다.
RubberDuck

3
null을 반환하는 대신 누군가해야 할 일에 대한 질문에 답하고 있다는 것을 알고 있지만 실제로 많은 점에 동의하지 않습니다. 그러나 우리는 언어에 국한된 것이 아니고 모든 규칙을 어기는 이유가 있습니다.
Liath

15

null여기서 실제로 문제가 아닙니다. 문제는 대부분의 현재 프로그래밍 언어가 누락 된 정보를 처리하는 방식입니다. 그들은이 문제를 진지하게 받아들이지 않습니다 (또는 적어도 대부분의 지구인들이 함정을 피하기 위해 필요한 지원과 안전을 제공하지 않습니다). 이것은 우리가 배운 모든 문제로 이어집니다 (Javas NullPointerException, Segfaults, ...).

더 나은 방법으로 해당 문제를 처리하는 방법을 살펴 보겠습니다.

다른 사람들은 Null-Object Pattern을 제안했습니다 . 때로는 적용 할 수 있다고 생각하지만 모든 크기에 딱 맞는 크기가없는 많은 시나리오가 있습니다. 그러한 경우, 정보가 없을 수있는 정보 소비자는 정보가 누락 된 경우 어떻게해야하는지 스스로 결정할 수 있어야합니다.

컴파일 타임에 널 포인터 (공극 안전)에 대해 안전을 제공하는 프로그래밍 언어가 있습니다. Kotlin, Rust, Swift와 같은 현대적인 예를 들겠습니다. 이러한 언어에서는 정보 누락 문제가 심각하게 고려되었으며 null을 사용하면 전혀 고통이 없습니다. 컴파일러는 nullpointer를 역 참조하지 못하게합니다.
Java에서는 @ Nullable / @ NotNull 어노테이션을 컴파일러 + IDE 플러그인과 함께 설정하여 동일한 효과에 도달하려고했습니다. 실제로 성공하지는 않았지만이 답변의 범위를 벗어났습니다.

가능한 부재를 나타내는 명시적이고 일반적인 유형은이를 처리하는 또 다른 방법입니다. 예를 들어 Java에는 java.util.Optional. 작동 가능 :
프로젝트 또는 회사 수준에서 규칙 / 지침을 설정할 수 있습니다

  • 고품질 타사 라이브러리 만 사용
  • 항상java.util.Optional 대신 사용하십시오null

귀하의 언어 커뮤니티 / 생태계는 컴파일러 / 통역사 보다이 문제를 해결하는 다른 방법을 생각해 냈습니다.


친절하게 정교하게 설명해 주시면 Java Optionals가 어떻게 null보다 낫습니까? 문서를 읽을 때 선택 사항에서 값을 얻으려고하면 값이 없으면 예외가 발생합니다. 그래서 우리는 같은 장소에있는 것 같습니다 : 점검이 필요하고 잊어 버린 경우 망했습니까?
gaazkam

3
@gaazkam 당신 말이 맞아, 컴파일 타임 안전을 제공하지 않습니다. 또한 Optional 자체는 또 다른 문제인 null 일 수 있습니다. 그러나 명시 적입니다 (변수는 null / doc 주석 일 가능성이 있습니다). 이것은 전체 코드베이스에 대해 코딩 규칙이 설정된 경우에만 실질적인 이점을 제공합니다. 일을 null로 설정할 수 없습니다. 정보가 없을 경우 옵션을 사용하십시오. 그것은 명시 성을 강요합니다. 그러면 일반적인 null-checks는 다음과 같이 호출됩니다.Optional.isPresent
marstato

8
@marstato null 점검을 대체 isPresent() 하는 것은 Optional의 권장 사용이 아니다
candied_orange

10

나는 널이 나쁘다는 진술에서 장점을 보지 못했다. 나는 그것에 관한 토론을 점검했고 그들은 나를 참을성 있고 짜증나게 만들었습니다.

실제로 무언가를 의미 할 때 널은 "마법의 가치"로 잘못 사용될 수 있습니다. 그러나 거기에 가려면 꽤 꼬인 프로그래밍을해야합니다.

널 (null)은 "아직 존재하지 않음"을 의미하며, 인수 인 경우 작성 (아직) 또는 (이미) 없어지거나 제공되지 않습니다. 그것은 상태가 아니며 모든 것이 빠져 있습니다. 모든 상태와는 다른 유효하고 의미있는 조건 인 모든 것이 생성되고 파괴되는 OO 설정에서.

null을 사용하면 런타임에 일종의 유형 안전 null 대안으로 컴파일 타임에 충돌합니다.

완전히 사실은 아니지만 변수를 사용하기 전에 null을 확인하지 않는다는 경고를받을 수 있습니다. 그리고 그것은 동일하지 않습니다. 목적이없는 개체의 리소스를 절약하고 싶지 않을 수 있습니다. 그리고 더 중요한 것은 원하는 행동을 얻기 위해 대안을 동일하게 확인해야 할 것입니다. 내가 잊어 버린 경우 런타임에 정의되지 않은 / 의도하지 않은 동작보다 NullReferenceException이 발생합니다.

알아야 할 한 가지 문제가 있습니다. 다중 스레드 컨텍스트에서는 null 검사를 수행하기 전에 로컬 변수에 먼저 할당하여 경쟁 조건으로부터 보호해야합니다.

널 (null)의 문제점은 많은 것들에 이르기까지 다양하다는 의미입니다. 따라서 정보가 파괴됩니다.

아니요, 아무 의미가 없어서 파괴 할 것이 없습니다. 변수 / 인수의 이름과 유형은 항상 무엇을 잃어 버렸는지 알 수 있습니다.

편집하다:

나는 함수형 프로그래밍에 대한 그의 다른 답변 중 하나에 링크 된 비디오 candied_orange의 절반 이며 매우 흥미 롭습니다. 특정 시나리오에서 유용성을 볼 수 있습니다. 지금까지 보았던 기능적 접근 방식은 코드 조각이 날아 다니며 일반적으로 OO 설정에서 사용될 때 울부 짖습니다. 그러나 나는 그 자리를 가지고 있다고 생각합니다. 어딘가에. 그리고 C #에서 발생할 때마다 혼란 스러울 것으로 생각되는 것을 숨기고 좋은 일을하는 언어가있을 것입니다. 대신 깨끗하고 실행 가능한 모델을 제공하는 언어입니다.

해당 기능 모델이 사용자의 사고 방식 / 프레임 워크 인 경우 문서화 된 오류 설명으로 문제를 해결하고 실제로 발신자가 누적 된 쓰레기를 처리 지점으로 끌어 올릴 수있는 대안이 없습니다. 분명히 이것은 함수형 프로그래밍이 작동하는 방식입니다. 그것을 제한이라고 부르고 새로운 패러다임이라고 부릅니다. 기능적인 제자들이 부정한 길을 조금 더 계속 나아가게하는 해킹이라고 생각할 수도 있습니다.이 새로운 프로그래밍 방식이 흥미롭고 새로운 가능성을 열어 줄 것입니다. 어쨌든, 저 세상에 들어서서, 전통적인 OO 방식으로 돌아가는 것 (예, 우리는 예외를 던질 수 있습니다, 죄송합니다)에서 개념을 고르는 것이 무의미 해 보입니다.

모든 개념은 잘못된 방식으로 사용될 수 있습니다. 내가 서있는 곳에서 제시된 "솔루션"은 null을 적절히 사용하기위한 대안이 아닙니다. 그들은 다른 세계에서 온 개념입니다.


9
널 (Null)은 그것이 무엇을 나타내는 지에 대한 지식을 파괴합니다. 조용히 무시해야 할 것은 없습니다. 잘못된 상태를 피하기 위해 시스템을 정지시킬 필요는 없습니다. 프로그래머가 망쳐 코드를 수정해야한다는 의미는 없습니다. 아무것도 존재하지 않는 것은 사용자가 존재하지 않고 정중하게 말해야 할 것을 요구했음을 의미합니다. 죄송합니다 이들 모두는 null로 인코딩되었습니다. 그로 인해 이들 중 하나를 null로 인코딩하면 아무도 당신이 무엇을 의미하는지 모른다고 놀라지 않아야합니다. 문맥에서 추측하도록 강요하고 있습니다.
candied_orange

3
@candied_orange 당신은 옵션 타입에 대해 똑같은 주장을 할 수 있습니다 None.
중복 제거기

3
@candied_orange 나는 아직도 당신이 무엇을 의미하는지 얻지 못합니다. 다른 종류의 아무것도? 열거 형을 사용해야했을 때 null을 사용한다면? 아무것도 하나도 없습니다. 무언가가없는 이유는 다양 할 수 있지만, 아무것도 아닌 것에 대한 적절한 반응이나 아무것도 변경하지 않습니다. 상점에 존재하지 않고 주목할만한 값을 예상하면 쿼리하거나 아무것도 얻지 못하는 순간에 로그를 던지거나 기록하지 않으면 메소드에 대한 인수로 널을 전달하지 않고 해당 메소드에서 파악하려고합니다. 왜 널 얻었 니? 널은 실수가 아닙니다.
Martin Maat

2
Null은 실수의 의미를 인코딩 할 기회가 있었기 때문에 실수입니다. 아무것도 이해하지 않아도 아무것도 처리하지 않아도됩니다. 0, null, NaN, 빈 문자열, 빈 세트, void, null 개체, 적용 할 수 없음, 구현되지 않은 예외는 여러 가지 형태로 제공되지 않습니다. 지금 알고있는 것을 다루고 싶지 않기 때문에 지금 알고있는 것을 잊지 않아도됩니다. 내가 -1의 제곱근을 취하도록 요청하면 예외를 던져 불가능하다는 것을 알려주고 모든 것을 잊거나 허수를 발명하고 알고있는 것을 보존 할 수 있습니다.
candied_orange

1
@MartinMaat 당신은 당신의 기대가 위반 될 때마다 함수가 예외를 던져야하는 것처럼 들리게합니다. 이것은 단순히 사실이 아닙니다. 처리해야 할 경우가 종종 있습니다. 만약 당신이 정말로 이것을
candied_orange

7

당신의 질문입니다.

그러나 내 순진함에서 비명을 지르는 경우가 있습니다. 때로는 가치가 없을 수도 있습니다!

거기 당신과 함께 완전히 탑승. 그러나 잠시 후 몇 가지주의 할 점이 있습니다. 그러나 먼저 :

널은 사악하므로 가능할 때마다 피해야합니다.

나는 이것이 잘 의도되었지만 지나치게 일반화 된 진술이라고 생각합니다.

널은 악이 아니다. 반 패턴이 아닙니다. 그것들은 모든 비용으로 피해야 할 것이 아닙니다. 그러나 널 (null) 확인에 실패하여 널이 오류발생하기 쉽습니다 .

그러나 null을 확인하지 못하면 null이 본질적으로 잘못 사용되었음을 증명하는 방법을 이해하지 못합니다.

null이 악의 인 경우는 배열 인덱스와 C ++ 포인터도 마찬가지입니다. 그들은 아니다. 그들은 발로 쉽게 쏠 수 있지만 모든 비용을 피할 수는 없습니다.

이 답변의 나머지 부분에서, 나는 "null은 악하다"라는 의도를보다 미묘한 " null은 책임감있게 다루어야한다 "에 맞추 겠다 .


당신의 솔루션.

전역 규칙으로 null을 사용하는 것에 대한 귀하의 의견에 동의하지만; 이 특정 경우에 null을 사용하는 것에 동의하지 않습니다.

아래 피드백을 요약하면 상속과 다형성의 목적을 오해하고있는 것입니다. 널 (null)을 사용한다는 당신의 주장은 타당하지만, 다른 방법이 왜 나쁜지에 대한 당신의 "증거"는 상속의 오용에 기반을두고 있으며, 당신의 포인트가 널 (null) 문제와는 관련이 없습니다.

대부분의 업데이트에는 당연히 플레이어가 연결되어 있습니다. 결국 어떤 플레이어가이 턴을했는지 알아야합니다. 그러나 일부 업데이트에는 플레이어와 의미있게 연결된 플레이어가 없을 수 있습니다.

이러한 업데이트가 의미가 다른 경우 (업데이트 된 경우) 두 가지 별도의 업데이트 유형이 필요합니다.

예를 들어 메시지를 고려하십시오. 오류 메시지와 IM 채팅 메시지가 있습니다. 그러나 매우 유사한 데이터 (문자열 메시지 및 발신자)를 포함 할 수 있지만 동일한 방식으로 작동하지 않습니다. 서로 다른 클래스로 별도로 사용해야합니다.

지금하고있는 일은 Player 속성의 null-ness에 따라 두 가지 업데이트 유형을 효과적으로 구분하는 것입니다. 이는 오류 코드의 존재 여부에 따라 IM 메시지와 오류 메시지를 결정하는 것과 같습니다. 작동하지만 최선의 방법은 아닙니다.

  • JS 코드는 이제 Player가없는 객체를 정의 된 속성으로받습니다. 두 경우 모두 값이 있는지 또는 없는지 확인해야하기 때문에 null 인 경우와 같습니다.

당신의 주장은 다형성의 잘못에 의존합니다. 당신이 반환하는 방법이 있다면 GameUpdate객체를, 일반적으로 지금까지 구분하는 신경 안 GameUpdate, PlayerGameUpdate또는 NewlyDevelopedGameUpdate.

기본 클래스는 완전히 작동하는 계약을 가져야합니다. 즉, 해당 속성은 파생 클래스가 아니라 기본 클래스에 정의되어 있습니다 (즉, 이러한 기본 속성 의 은 파생 클래스에서 재정의 될 수 있음).

이것은 당신의 논증을 무디게합니다. 모범 사례에서는 GameUpdate객체에 플레이어가 있거나 없는 것을 신경 쓰지 않아야합니다 . 의 Player속성에 액세스하려는 경우 GameUpdate비논리적 인 일을하는 것입니다.

C #과 같은 유형이 지정된 언어는 단순히 속성이 없기 때문에 속성에 액세스하려고 시도 조차 수 없습니다. Javascript는 접근 방식에서 상당히 여유가 없으며 사전 컴파일이 필요하지 않으므로 수정하지 않아도되어 런타임에 폭발 할 수 있습니다.PlayerGameUpdateGameUpdate

  • 또 다른 nullable 필드가 GameUpdate 클래스에 추가되면 다중 상속을 사용 하여이 desing을 계속할 수 있어야하지만 MI는 자체적으로 (보다 숙련 된 프로그래머에 따르면) 악의적이며 더 중요한 것은 C #이 아닙니다. 사용하지 못하도록하십시오.

nullable 속성을 추가하여 클래스를 만들면 안됩니다. 기능적으로 고유 한 유형의 게임 업데이트를 기반으로 클래스를 작성해야 합니다 .


일반적으로 null 문제를 피하는 방법은 무엇입니까?

가치가 없다는 것을 의미있게 표현할 수있는 방법에 대해 자세히 설명하는 것이 적절하다고 생각합니다. 이것은 특정 순서로 솔루션 (또는 나쁜 접근 방식) 모음입니다.

1. 어쨌든 null을 사용하십시오.

이것이 가장 쉬운 방법입니다. 그러나 수많은 null 검사에 서명하고 null 참조 예외 문제를 해결하지 못한 경우 (그러지 않을 경우)

2. null이 아닌 의미없는 값을 사용하십시오.

간단한 예는 indexOf()다음과 같습니다.

"abcde".indexOf("b"); // 1
"abcde".indexOf("f"); // -1

대신에 null당신은 얻는다 -1. 기술적 인 수준에서 이것은 유효한 정수 값입니다. 그러나, 음의 값은이다 무의미한 인덱스가 양의 정수가 될 것으로 예상된다대로 대답은.

논리적으로, 이것은 반환 유형이 의미있게 반환 될 수있는 것보다 더 많은 값을 허용하는 경우에만 사용할 수 있습니다 (indexOf = 양의 정수; int = 음수 및 양의 정수)

참조 유형의 경우이 원칙을 계속 적용 할 수 있습니다. 예를 들어 정수 ID의 엔터티가있는 경우 null이 아닌 ID가 -1로 설정된 더미 객체를 반환 할 수 있습니다.
객체를 실제로 사용할 수 있는지 여부를 측정 할 수있는 "더미 상태"를 정의하기 만하면됩니다.

문자열 값을 제어하지 않으면 미리 정해진 문자열 값에 의존해서는 안됩니다. 빈 개체를 반환 할 때 사용자 이름을 "null"로 설정하는 것을 고려할 수 있지만 Christopher Null이 서비스에 등록 할 때 문제가 발생합니다 .

3. 대신 예외를 던져라.

아뇨 논리적 흐름에 대한 예외를 처리해서는 안됩니다.

즉, (nullreference) 예외를 숨기고 싶지 않고 적절한 예외를 표시하는 경우가 있습니다. 예를 들면 다음과 같습니다.

var existingPerson = personRepository.GetById(123);

이것은 PersonNotFoundExceptionID가 123 인 사람이 없을 때 (또는 유사한) 것을 던질 수 있습니다 .

분명히 이것은 항목을 찾지 못하면 추가 처리가 불가능한 경우에만 허용됩니다. 항목을 찾을 수없고 응용 프로그램을 계속할 수 있으면 예외를 던져서는 안됩니다 . 나는 이것을 충분히 강조 할 수 없다.


5

널이 나쁜 이유는 결 측값이 널로 인코딩되지 않고 모든 참조 값이 널이 될 수 있다는 것입니다. C #이 있으면 어쨌든 잃어 버릴 것입니다. 참조 유형이 이미 선택 사항이므로 일부 옵션을 사용하는 점이 표시되지 않습니다. 그러나 Java의 경우 @Notnull 주석 이 있습니다. 패키지 수준에서 설정할 수있는 것처럼 보이고 누락 된 값의 경우 주석 @Nullable을 사용할 수 있습니다.


예! 문제는 무의미한 기본값입니다.
중복 제거기

동의하지 않습니다. null을 피하는 스타일로 프로그래밍하면 참조 변수가 null이되어 null이되어서는 안되는 참조 변수가 줄어 듭니다. 100 %는 아니지만 90 % 일 가능성이 있으며 이는 IMO의 가치입니다.
복구 상태 Monica

1

널은 악한 것이 아니며, 어떤 시점에서 널처럼 보이는 것을 다루지 않고 대안을 구현할 수있는 방법은 현실적으로 없습니다.

그러나 널은 위험 합니다. 다른 저수준 구조와 마찬가지로 잘못하면 아래에 아무것도 없습니다.

null에 대해 유효한 인수가 많이 있다고 생각합니다.

  • 이미 높은 수준의 도메인에 있다면 낮은 수준의 모델을 사용하는 것보다 안전한 패턴이 있습니다.

  • 저수준 시스템의 장점이 필요하고 적절한주의를 기울일 준비가되어 있지 않으면 저수준 언어를 사용해서는 안됩니다.

  • ...

이것들은 모두 유효하며 게터와 세터 등을 작성하는 노력을 기울일 필요가없는 것은 그 조언을 따르지 않은 일반적인 이유로 간주됩니다. 많은 프로그래머들이 널이 위험하고 게으르다는 결론에 이르렀다는 것은 놀라운 일이 아니지만, 다른 많은 "유니버설"충고와 같이 그것들은 그들이 말하는 것처럼 보편적이지 않다.

언어를 쓴 훌륭한 사람들은 누군가에게 유용 할 것이라고 생각했습니다. 귀하가 이의 제기를 이해하고 여전히 귀하에게 옳다고 생각한다면, 다른 어느 누구도 더 잘 알지 못할 것입니다.


문제는 사람들이 주장하는 것처럼 "보편적 조언"은 일반적으로 "보편적"으로 표현되지 않습니다. 그러한 조언의 원천을 찾으면 경험 많은 프로그래머가 알고있는주의 사항에 대해 이야기합니다. 다른 사람이 조언을 읽을 때, 그 경고를 무시하고 "보편적 조언"부분 만 기억하는 경향이 있기 때문에, 그 조언을 다른 사람들과 관련시킬 때, 그것이 원래 의도 한 것보다 훨씬 더 "보편적"으로 나옵니다. .
Nicol Bolas

1
@NicolBolas, 당신 말이 맞지만, 원래 출처는 대부분의 사람들이 인용하는 조언이 아니며, 릴레이 된 메시지입니다. 내가 원했던 요점은 단지 많은 프로그래머들에게 'X는 절대로 X는 악하고 나쁜 것은 무엇이든'이라고 들었고, 당신이 말했듯이 정확하게 많은 경고가 누락되었다는 것입니다. 어쩌면 그들은 떨어졌을 수도 있고, 존재하지 않았을 수도 있습니다. 최종 결과는 같습니다.
drjpizzle

0

Java에는 모든 값에 안전하게 액세스하기 Optional위한 명시 적 ifPresent+ 람다 클래스가 있습니다. 이것은 JS에서도 가능합니다.

이 StackOverflow 질문을 참조하십시오 .

그건 그렇고 : 많은 순수 주의자는이 사용법이 모호하다고 생각하지만 그렇게 생각하지는 않습니다. 선택적 기능이 존재합니다.


에 대한 참조는 할 수 없습니다 java.lang.Optionalnull도?
중복 제거기

@Deduplicator 아니요, Optional.of(null)예외를 던지고 Optional.ofNullable(null)줄 것 Optional.empty()입니다.
Joop Eggen

그리고 Optional<Type> a = null?
중복 제거기

@Deduplicator true, 그러나 거기에 사용해야합니다 Optional<Optional<Type>> a = Optional.empty();;)-다른 말로 JS (및 다른 언어)에서는 그러한 것이 가능하지 않습니다. 기본값을 가진 스칼라가 할 것입니다. Java는 열거 형이있을 수 있습니다. JS 의심합니다 : Optional<Type> a = Optional.empty();.
Joop Eggen

따라서, 우리는 하나의 간접적이고 잠재적 null이거나 비어있는 것에서 두 개의 더해진 메소드에 대한 추가 메소드 로 옮겼습니다 . 그것은 꽤 업적입니다.
중복 제거기

0

CAR Hoare는 널을 "십억 달러의 실수"라고 불렀습니다. 그러나 그는 솔루션이 "어딘가에 널이 없음"이 아니라 "널링 가능하지 않은 포인터를 기본값으로 사용하고 의미 상 필요한 경우에만 널"이라고 생각하는 것이 중요합니다.

실수를 반복하는 언어에서 널 (null) 문제는 함수가 널 입력 불가능 데이터를 예상한다고 말할 수 없다는 것입니다. 그것은 언어에서 근본적으로 표현할 수 없습니다. 이로 인해 함수에 쓸모없는 불필요한 null 처리 상용구가 많이 포함되고 null 검사를 잊어 버리는 것이 일반적인 버그 원인입니다.

표현력의 근본적인 부족을 해킹하기 위해 일부 커뮤니티 (예 : 스칼라 커뮤니티)는 null을 사용하지 않습니다. 스칼라에서는 null 타입 T의 type Option[T]을 원한다면 type 인수 를 사용하고, nullable이 아닌 값을 원한다면 T. 누군가가 코드에 null을 전달하면 코드가 폭발합니다. 그러나 호출 코드는 버그가있는 코드로 간주됩니다. Option일반적인 null 처리 패턴이 .map(f)or 와 같은 라이브러리 함수로 추출되므로 null을 대체하는 것이 좋습니다 .getOrElse(someDefault).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.