방어 프로그래밍이란 무엇입니까?

14870 단어

방어 프로그래밍이란 무엇입니까?



Defensive programming is a form of defensive design intended to develop programs that are capable of detect potential security abnormalities and make predetermined response - Wikipedia



즉, 방어 프로그래밍은 자신의 믿음이 신뢰할 수 없다고 생각하거나 최악의 경우를 가정하기 때문에 발생하지 않거나 발생할 수 있다고 생각하지 않는 경우를 처리하기 위해 코드를 작성하는 것입니다. 미친 입력으로부터 자신과 프로그램을 보호해야 합니다.

예를 들어, 두 개의 숫자를 더하고 출력을 산출하는 함수를 보자.

func add(a, b int) (int, error) {
    if a == 0 || b == 0 {
        // gracefully return and error
        return 0, errors.New("can't add zero values")
    }

    // finally compute the function
    return a + b, nil
}

func main() {
    result, err := add(10, 30)
    if err != nil {
        log.Fatalln(err)
    }
    log.Println(result)
}



여기에서 결과 작업이 완료되기 전에 오류가 확인됩니다.

코드 검사 도구를 사용하여 모든 코드 경로를 다루는 단위 테스트로 논리적 오류와 싸울 수 있습니다. 예를 들어 0 값을 방지하는 테스트를 작성할 수 있습니다.

package main

import "testing"

func TestAdd(t *testing.T) {
    output, err := add(0, 1)

    if err != nil {
        t.Fatalf(`TestAdd = %d, error -> %s`, output, err)
    }
}



어떤 실패

Running tool: /opt/go/bin/go test -timeout 30s -run ^TestAdd$ github.com/navicstein/def

--- FAIL: TestAdd (0.00s)
    /home/navicstein/Idea/def/main_test.go:9: TestAdd = 0, error -> can't add zero values
FAIL
FAIL    github.com/navicstein/def   0.002s
FAIL


C 또는 Go와 같은 정적 언어에서 컴파일러는 예를 들어 숫자가 예상되는 곳에 문자열을 전달하지 못하게 하는 것과 같이 온전성 검사 중 일부를 수행합니다.

방지해야 할 세 가지 오류 소스가 있습니다.
  • 코드 자체의 논리적 오류.
  • 입력 데이터, 특히 사용자 제공 입력의 오류.
  • 환경 오류

  • 또 다른 실제 예를 살펴보겠습니다. 이 예에서는 비디오를 실제로 .mp4 비디오 파일로 변환한다고 가정합니다.

    package main
    
    import (
        "errors"
        "log"
        "path/filepath"
        "strings"
        "time"
    
        "golang.org/x/exp/slices"
    )
    
    type VideoParams struct {
        Url          string
        AudioBitrate string
        VideoBitrate string
        VideoCodec   string
        AudioCodec   string
    }
    
    // ConvertAnyVideoToMp4 converts any video to mp4
    func ConvertAnyVideoToMp4(args VideoParams) error {
        if args.Url == "" {
            return errors.New("an input URL is required, please provide one")
        }
    
        var (
            fileExt = filepath.Ext(args.Url)
            exts    = []string{".flv", ".avi"}
        )
    
        // don't convert video is already an mp4 file
        if strings.ToLower(fileExt) == ".mp4" {
            return errors.New("video is alread an mp4 file, nothing to do")
        }
    
        // validate against supported files
        if !slices.Contains(exts, fileExt) {
            return errors.New("unsupported video file")
        }
    
        // Here, we're just supplying defaults as we can tolerate the nil arguments
        if args.AudioBitrate == "" {
            args.AudioBitrate = "8k"
        }
    
        if args.VideoBitrate == "" {
            args.VideoBitrate = "30k"
        }
    
        if args.AudioCodec == "" {
            args.AudioCodec = "mp3"
        }
    
        if args.VideoCodec == "" {
            args.VideoCodec = "4264"
        }
    
        doneCh := make(chan bool, 1)
    
        func() {
            log.Printf("Converting with: %#v", args)
            time.AfterFunc(time.Second*5, func() {
                doneCh <- true
            })
        }()
    
        if <-doneCh {
            log.Println("Finished converting video to mp4")
        }
    
        return nil
    }
    
    


    그리고 사용 파일에서

        args := VideoParams{
            Url: "https://sample-videos.com/video123/flv/720/big_buck_bunny_720p_1mb.flv",
        }
    
        if err := ConvertAnyVideoToMp4(args); err != nil {
            log.Fatalln(err)
        }
    


    사용자가 지정하지 않은 속성에 대한 기본값이 있음을 알 수 있습니다.

    ❯ go run .
    2022/09/11 03:40:12 Converting with: main.VideoParams{Url:"https://sample-videos.com/video123/flv/720/big_buck_bunny_720p_1mb.flv", AudioBitrate:"8k", VideoBitrate:"30k", VideoCodec:"4264", AudioCodec:"mp3"}
    2022/09/11 03:40:17 Finished converting video to mp4
    


    위의 예에서는 기본값을 확인하고 설정한 다음 사용자 정의 속성으로 기본값을 재정의하지만 함수가 수행할 작업에 대한 명확한 표현을 제공하므로 함수를 실제로 구현하기 전에 테스트 사례를 작성하는 것이 좋습니다.

    방어 프로그래밍과 예외 처리의 차이점



    "방어적 프로그래밍"이라는 용어는 두 가지 보완적인 의미를 갖는 것으로 보입니다. 첫 번째 의미에서,
    용어는 가정을 명시적으로 주장하는 주장에 기반한 프로그래밍 스타일을 설명하는 데 사용됩니다.
    소프트웨어가 올바르게 작동하는 한 사실이어야 합니다.
    그러나 다른 의미에서 "방어적 프로그래밍"은 만드는 것을 목표로 하는 프로그래밍 스타일을 나타냅니다.
    더 넓은 범위의 입력을 받아들임으로써 오류에 대한 작업이 더 강력해집니다.

    하는 동안
    예외 처리는 컴퓨터 프로그램이 실행될 때 원치 않거나 예기치 않은 이벤트에 응답하는 프로세스입니다.

    집으로 가져갈 몇 가지 핵심 개념



    Anything that can go wrong will go wrong - Murphy's Law


  • 오류 조건이 발생하면 코드에서 이를 처리해야 합니다(메모리 부족, 디스크 가득 참, 파일 누락, 파일 손상, 네트워크 오류 등)
  • 소프트웨어는 다양한 오류 조건에서 어떻게 작동하는지 확인하기 위해 테스트해야 합니다
  • 즉, 오류가 발생할 것이라고 가정하고 발생했을 때 오류를 감지하는 코드를 작성하십시오.
  • 프로그램이 실행될 때 상태를 확인하고 독자가 해당 프로그램이 작동하는 방식을 이해하도록 돕기 위해 프로그램에 어설션을 넣습니다.
  • 사전 조건을 사용하여 함수에 대한 입력이 사용하기에 안전한지 확인하십시오.
  • 사후 조건을 사용하여 함수의 출력이 사용하기에 안전한지 확인하십시오.
  • 코드를 작성하기 전에 테스트를 작성하여 해당 코드가 수행해야 하는 작업을 정확히 결정하는 데 도움을 줍니다.

  • https://faculty.cs.byu.edu/~rodham/cs240/lecture-notes/Lecture-16-ErrorHandling&DefensiveProgramming/Lecture-16-ErrorHandlingAndDefensiveProgramming.pdf

    https://www.state-machine.com/doc/Samek0308.pdf

    https://glebbahmutov.com/blog/defensive-coding-examples/

    좋은 웹페이지 즐겨찾기