불변성 수용(프로그래밍 및 인프라)

가변성 🚨



프로그래머이고 Java, Python 및 Go와 같은 언어에 대한 경험이 있는 경우 가변성의 이점과 단점을 알고 있을 것입니다.

가변성의 문제는 주로 다음과 같습니다.

  • 복잡성 증가: 어떤 함수가 값을 변경합니까? 이 속성이 null인 이유는 무엇입니까?

  • 동시성: 동일한 변수를 수정하는 스레드

  • 불변 데이터 구조를 사용하면 스레드와 함수 간에 걱정 없이 데이터를 공유할 수 있습니다.

    인프라 세계에서도 우리는 서버를 배포하고 지속적으로 업데이트하고 수정하여 모든 변경 사항을 추적하고 처음부터 새로운 환경을 만드는 것이 매우 어려웠습니다.

    불변 인프라는 서버가 수정되지 않는 또 다른 인프라 패러다임입니다. 업데이트가 필요한 경우 이전 서버를 대체하기 위해 새 서버를 구축하고 프로비저닝합니다.

    Effective Java라는 책에서 저자는 메서드와 클래스에서 final 키워드를 사용하는 것을 옹호합니다. 왜요?

    The final keyword is a non-access modifier used for classes, attributes, and methods, which makes them non-changeable (impossible to inherit or override).

    The final keyword is useful when you want a variable to always store the same value, like PI



    Java와 같은 언어에서 Go 및 Python 객체는 기본적으로 변경 가능합니다. 이로 인해 당면한 문제에 대해 추론하기가 훨씬 더 어려워집니다.

    Chef, Puppet 및 Ansible과 같이 일반적으로 기본적으로 변경 가능한 인프라 패러다임을 사용하는 구성 관리 도구를 사용하는 인프라 세계에서도 동일한 일이 발생합니다.

    구조에 대한 불변성 ⛑



    이 아이디어는 변수가 불변이므로 변수를 값으로 설정한 후에는 값을 변경할 수 없는 함수형 프로그래밍에서 영감을 받았습니다. 무언가를 업데이트해야 하는 경우 새 변수를 만듭니다.

    값은 절대 변경되지 않으므로 코드에 대해 추론하기가 더 쉽습니다.

    Code example (Go/Clojure)

    좋은 소식은 이 문제를 극복할 수 있다는 것입니다! 😎

    이동 포인터


  • 참조 대신 값을 전달합니다.

  • package main
    
    import (
        "fmt"
        "math/rand"
        "strconv"
        "strings"
    )
    
    type Book struct {
        Author string
        Title  string
        Pages  int
    }
    
    func (book Book) GetPagesWithCode() string {
        var n = rand.Intn(200)
        book.Pages -= n
        return "The " + strings.ToUpper(book.Title) + " book has " + strconv.Itoa(book.Pages) + " pages"
    }
    
    func main() {
    
        var book = Book{Author: "Rich Hickey", Title: "Clojure for the Brave & True", Pages: 232}
        fmt.Printf("1) %+v\n", book)
        changeAuthor(&book, "Daniel Higginbotham")
        fmt.Printf("2) %+v\n", book)
        fmt.Println(book.GetPagesWithCode())
        fmt.Printf("3) %+v\n", book)
    
    }
    
    func changeAuthor(book *Book, author string) {
        book.Author = author
    }
    
    


    산출:
    메서드에서 페이지를 업데이트해도 데이터는 동일하게 유지됩니다.

    1) {Author:Rich Hickey Title:Clojure for the Brave & True Pages:232}
    2) {Author:Daniel Higginbotham Title:Clojure for the Brave & True Pages:232}
    The CLOJURE FOR THE BRAVE & TRUE book has 151 pages
    3) {Author:Daniel Higginbotham Title:Clojure for the Brave & True Pages:232}


    클로저


  • 새 값을 반환하는 함수를 만듭니다.

  • (ns main.core
      (:require [clojure.string :as s])
      (:gen-class)
      )
    
    (defn get-pages-with-code [book]
      (str "The " (s/upper-case (:title book)) " book has " (:pages book) " pages")
      )
    
    (defn change-author [book author]
      (assoc book :author author))
    
    
    (defn -main
      [& args]
      (let [book {:author "Rich Hickey", :title "Clojure for the Brave & True", :pages 232}
            new-book (change-author book "Daniel Higginbotham")]
        (println "1)" book)
        (println "2)" new-book)
        (println "3)" (get-pages-with-code book))
        )
      )
    

    산출:
    데이터는 절대 변경되지 않으며 새로운 값을 생성할 뿐입니다.

    1) {:author Rich Hickey, :title Clojure for the Brave & True, :pages 232}
    2) {:author Daniel Higginbotham, :title Clojure for the Brave & True, :pages 232}
    3) The CLOJURE FOR THE BRAVE & TRUE book has 232 pages


    테라포밍


  • 현재 서버를 업데이트하는 대신 새 서버 배포

  • resource "aws_instance" "george_server" {
      ami           = "ami-0fb653ca2d3203ac1"
      instance_type = "t2.micro"
    }
    

    완전히 새로운 서버

    resource "aws_instance" "george_server" {
      ami           = "ami-0CCC3ca2d32CCC1"
      instance_type = "t2.micro"
    }
    


    서버는 절대 변경되지 않기 때문에 배포된 항목에 대해 추론하기가 훨씬 쉽습니다.

    결론



    변수와 개체를 변경할 수 있는 프로그램 부분을 제어하면 보다 강력하고 예측 가능한 소프트웨어를 작성할 수 있습니다.

    불변성을 수용하세요 🔥

    severity = :mild
    error_message = "OH GOD! IT'S A DISASTER! WE'RE "
    if severity == :mild
      error_message = error_message + "MILDLY INCONVENIENCED!"
    else
      error_message = error_message + "DOOOOOOOMED!"
    end
    You might be tempted to do something similar in Clojure:
    



    (def severity :mild)
    (def error-message "OH GOD! IT'S A DISASTER! WE'RE ")
    (if (= severity :mild)
      (def error-message (str error-message "MILDLY INCONVENIENCED!"))
      (def error-message (str error-message "DOOOOOOOMED!")))
    


  • https://www.braveclojure.com/do-things/
  • 좋은 웹페이지 즐겨찾기