偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

告別配置復(fù)雜性:領(lǐng)域特定語言(DSL)能幫你嗎?

開發(fā) 前端
如果您讀到這里,您可能已經(jīng)猜到我認(rèn)為配置語言并不是解決配置復(fù)雜性的最佳方案。每種語言都有其優(yōu)缺點(diǎn),但沒有任何一種語言能帶來顯著的改變。

譯自:Can Configuration Languages (config DSLs) solve configuration complexity?[1]

作者:Brian Grant

配置語言能否顯著降低配置復(fù)雜性?

過去幾年涌現(xiàn)出大量旨在生成配置的領(lǐng)域特定語言 (DSL),即配置語言:HCL[2],Dhall[3],Jsonnet[4],Starlark[5],CUE[6],Nickel[7],KCL[8],Pkl[9],以及其他[10]。我敢肯定至少有15種[11]。我通過包含表達(dá)式、條件語句、變量和其他語法結(jié)構(gòu)來區(qū)分這些語言和 JSON、XML、TOML、INI 等數(shù)據(jù)序列化語言,這些結(jié)構(gòu)有助于根據(jù)輸入生成多個(gè)具體的配置作為輸出。我將 YAML 歸類為數(shù)據(jù)序列化類別。YAMLScript[12] 比較新,我還沒有看到任何使用案例,因此不會(huì)介紹它。有關(guān)不同類型語言的更詳細(xì)細(xì)分,請參閱KCL 項(xiàng)目的這篇文章[13],該文章還比較了 KCL 與許多這些語言[14]。

為什么有人會(huì)選擇使用配置語言來編寫配置生成器/模板,而不是通用語言或模板語言(例如,Go 模板、Jinja、Mustache)?

對于工具構(gòu)建者而言,與通用語言相比,一個(gè)好處是這些語言(大多)是解釋型語言,并且可以嵌入到工具中,盡管模板語言也具有此特性。配置語言也可能比通用語言或模板語言更容易進(jìn)行靜態(tài)分析,并且可以輕松地確保它們不會(huì)產(chǎn)生副作用[15]。

除了根據(jù)自己的喜好塑造語言[16]之外,創(chuàng)建新的配置語言的好處還在于它可以更好地控制包和注冊表系統(tǒng)以及標(biāo)準(zhǔn)庫。事實(shí)上,其中一些語言最初是為特定工具創(chuàng)建的[17],例如 Terraform 的 HCL,Bazel 的 Starlark Bazel[18],Nix 包管理器的 Nickel Nix 包管理器[19],以及 KusionStack 的 KCL KusionStack[20]

對于用戶而言,語法可能比通用語言更簡潔。此外,我讀到一些非程序員發(fā)現(xiàn) HCL 與腳本語言(如 shell、awk 和/或 perl?)足夠相似,與 Python 和 Typescript 等通用語言相比更容易上手。對于程序員而言,使用熟悉的通用語言[21] 是 Pulumi 等工具的一個(gè)賣點(diǎn),但也許配置語言可以在多個(gè)通用語言用于應(yīng)用程序的環(huán)境中提供一個(gè)中立的中間地帶。與模板語言相比,配置語言具有更強(qiáng)大的表達(dá)能力,并且通常具有更高的類型安全性和模式驗(yàn)證能力。

當(dāng)然,每位語言設(shè)計(jì)者在設(shè)計(jì)語言時(shí)都有一些具體目標(biāo)。例如,CUE[22] 基于從 Google 內(nèi)部配置語言中吸取的經(jīng)驗(yàn)教訓(xùn)(Jsonnet[23] 也是如此),CUE 的一個(gè)目標(biāo)是通過不允許覆蓋來更容易確定最終值設(shè)置的位置[24]。Dhall 的一個(gè)目標(biāo)是使導(dǎo)入安全[25]。Starlark 是一種可嵌入的 Python 方言[26],對于熟悉 Python 的人來說很熟悉。Jsonnet 是JSON 的超集[27]。Nickel 中的類型是可選的[28]。Pkl[29]……等等。至少從編程語言設(shè)計(jì)的角度來看,它們很有趣。好的,這些語言看起來是什么樣的?由于我不精通大多數(shù)這些語言,我使用了Claude來生成每個(gè)語言的Kubernetes Deployment示例,其中資源名稱、標(biāo)簽值和容器鏡像都是參數(shù)化的。我不得不說,我對Claude印象非常深刻。Claude包含了如何運(yùn)行每個(gè)工具的說明,提到了每種語言的一些好處,并提供了使用特定語言功能進(jìn)一步改進(jìn)的建議。我將結(jié)果與我能找到的其他示例進(jìn)行了比較,但沒有通過這些工具運(yùn)行它們。這只是為了說明這些語言的特點(diǎn)。

以下是Deployment的YAML,其中包含一些屬性值,這些值是字符串、整數(shù)和布爾值,以及映射和數(shù)組/列表:

apiVersion: apps/v1
kind:Deployment
metadata:
labels:
    app:mydep
name:mydep
namespace:example
spec:
replicas:3
selector:
    matchLabels:
      app:mydep
template:
    metadata:
      labels:
        app:mydep
    spec:
      dnsPolicy:ClusterFirst
      containers:
      -image:nginx:latest
        name:nginx
        ports:
        -containerPort: 8080

使用Kubernetes 提供程序[30] 的HCL:

# Variables
variable "deployment_name" {
  description = "Name of the Kubernetes deployment"
  type = string
}

variable "container_image" {
  description = "Container image to deploy"
  type = string
}

# Deployment resource
resource "kubernetes_deployment" "deployment" {
  metadata {
    name      = var.deployment_name
    namespace = "example"
    labels = {
      app = var.deployment_name
    }
  }

  spec {
    replicas = 3
    selector {
      match_labels = {
        app = var.deployment_name
      }
    }
    template {
      metadata {
        labels = {
          app = var.deployment_name
        }
      }
      spec {
        dns_policy = "ClusterFirst"
        container {
          name  = "nginx"
          image = var.container_image
          port {
            container_port = 8080
          }
        }
      }
    }
  }
}

Dhall (官方示例[31]):

-- Type definitions for our configuration
let Kubernetes =
  https://raw.githubusercontent.com/dhall-lang/dhall-kubernetes/master/package.dhall
let deploymentName : Text = "mydep"
let containerImage : Text = "nginx:latest"
let deploymentLabels =
  toMap { app = deploymentName }
let containerPort =
  Kubernetes.ContainerPort::{
    , containerPort = 8080
  }
let container =
  Kubernetes.Container::{
    , name = "nginx"
    , image = Some containerImage
    , ports = Some [ containerPort ]
  }
let podTemplateSpec =
  Kubernetes.PodTemplateSpec::{
    , metadata = Some Kubernetes.ObjectMeta::{ labels = Some deploymentLabels }
    , spec = Some Kubernetes.PodSpec::{
      , containers = [ container ]
      , dnsPolicy = Some "ClusterFirst"
    }
  }
let deploymentSpec =
  Kubernetes.DeploymentSpec::{
    , replicas = Some 3
    , selector = Kubernetes.LabelSelector::{ matchLabels = Some deploymentLabels }
    , template = podTemplateSpec
  }
in Kubernetes.Deployment::{
  , metadata = Kubernetes.ObjectMeta::{
    , name = Some deploymentName
    , namespace = Some "example"
    , labels = Some deploymentLabels
  }
  , spec = Some deploymentSpec
}

Jsonnet (更多Kubernetes示例[32]):

// Input parameters
local params = {
  deploymentName: 'mydep',
  containerImage: 'nginx:latest',
};

// Helper to generate consistent labels
local labels = {
  app: params.deploymentName,
};

// Main deployment definition
{
  apiVersion: 'apps/v1',
  kind: 'Deployment',
  metadata: {
    name: params.deploymentName,
    namespace: 'example',
    labels: labels,
  },
  spec: {
    replicas: 3,
    selector: {
      matchLabels: labels,
    },
    template: {
      metadata: {
        labels: labels,
      },
      spec: {
        dnsPolicy: 'ClusterFirst',
        containers: [
          {
            name: 'nginx',
            image: params.containerImage,
            ports: [
              {
                containerPort: 8080,
              },
            ],
          },
        ],
      },
    },
  },
}

CUE (Kubernetes 教程[33]) — 我刪除了模式,因?yàn)樗赡芤驯粚?dǎo)入:

// Input parameters
params: {
  deploymentName: string
  containerImage: string
}

// Default values
params: {
  deploymentName: "mydep"
  containerImage: "nginx:latest"
}

// Deployment configuration
deployment: #Deployment & {
  metadata: {
    name: params.deploymentName
    namespace: "example"
    labels: {
      app: params.deploymentName
    }
  }
  spec: {
    replicas: 3
    selector: {
      matchLabels: {
        app: params.deploymentName
      }
    }
    template: {
      metadata: {
        labels: {
          app: params.deploymentName
        }
      }
      spec: {
        containers: [{
          name: "nginx"
          image: params.containerImage
          ports: [{
            containerPort: 8080
          }]
        }]
      }
    }
  }
}

// Output the deployment
deployment

Pkl (示例[34]):

module deployment

import "package://pkg.pkl-lang.org/k8s/apps/v1/1.27" as apps
import "package://pkg.pkl-lang.org/k8s/core/v1/1.27" as core

// Input parameters
deployCfg {
  name: String = "mydep"
  image: String = "nginx:latest"
}

// Create deployment using official K8s types
output = new apps.Deployment {
  metadata {
    name = deployCfg.name
    namespace = "example"
    labels = new {
      app = deployCfg.name
    }
  }

  spec {
    replicas = 3
    
    selector {
      matchLabels = new {
        app = deployCfg.name
      }
    }
    
    template {
      metadata {
        labels = new {
          app = deployCfg.name
        }
      }
      
      spec {
        dnsPolicy = "ClusterFirst"
        
        containers = List(
          new core.Container {
            name = "nginx"
            image = deployCfg.image
            ports = List(
              new core.ContainerPort {
                containerPort = 8080
              }
            )
          }
        )
      }
    }
  }
}

Nickel (示例[35]):

# Type contracts
let DeploymentConfig = {
  name | Str,
  image | Str,
}

# Function to generate labels
let makeLabels = fun name => {
  app = name
}

# Main deployment generator function
let makeDeployment = fun config | DeploymentConfig => {
  apiVersion = "apps/v1",
  kind = "Deployment",
  metadata = {
    name = config.name,
    namespace = "example",
    labels = makeLabels config.name,
  },
  spec = {
    replicas = 3,
    selector = {
      matchLabels = makeLabels config.name,
    },
    template = {
      metadata = {
        labels = makeLabels config.name,
      },
      spec = {
        dnsPolicy = "ClusterFirst",
        containers = [
          {
            name = "nginx",
            image = config.image,
            ports = [
              {
                containerPort = 8080,
              },
            ],
          },
        ],
      },
    },
  },
}

# Default configuration
let defaultConfig = {
  name = "mydep",
  image = "nginx:latest",
}

# Generate the deployment with default config
makeDeployment defaultConfig

KCL (示例[36]):

import k8s.api.apps.v1 as appsv1
import k8s.api.core.v1 as corev1

# Configuration parameters
schema DeploymentConfig:
    name: str = "mydep"
    image: str = "nginx:latest"

# Configuration values
config = DeploymentConfig {}

# Generate deployment using standard library types
deployment = appsv1.Deployment {
    metadata = corev1.ObjectMeta {
        name = config.name
        namespace = "example"
        labels.app = config.name
    }
    spec = appsv1.DeploymentSpec {
        replicas = 3
        selector = corev1.LabelSelector {
            matchLabels.app = config.name
        }
        template = corev1.PodTemplateSpec {
            metadata = corev1.ObjectMeta {
                labels.app = config.name
            }
            spec = corev1.PodSpec {
                dnsPolicy = "ClusterFirst"
                containers = [
                    corev1.Container {
                        name = "nginx"
                        image = config.image
                        ports = [
                            corev1.ContainerPort {
                                containerPort = 8080
                            }
                        ]
                    }
                ]
            }
        }
    }
}

Starlark (示例[37]):

# Helper function to create consistent labels
def make_labels(name):
    return {"app": name}

# Main deployment generator function
def make_deployment(name = "mydep", image = "nginx:latest"):
    """Creates a Kubernetes deployment configuration.
    
    Args:
        name: The name of the deployment
        image: The container image to deploy
    
    Returns:
        Dictionary containing the deployment configuration
    """
    return {
        "apiVersion": "apps/v1",
        "kind": "Deployment",
        "metadata": {
            "name": name,
            "namespace": "example",
            "labels": make_labels(name),
        },
        "spec": {
            "replicas": 3,
            "selector": {
                "matchLabels": make_labels(name),
            },
            "template": {
                "metadata": {
                    "labels": make_labels(name),
                },
                "spec": {
                    "dnsPolicy": "ClusterFirst",
                    "containers": [
                        {
                            "name": "nginx",
                            "image": image,
                            "ports": [
                                {
                                    "containerPort": 8080,
                                },
                            ],
                        },
                    ],
                },
            },
        },
    }

# Default deployment configuration
deployment = make_deployment()

def main(ctx):
    """Main entry point for Starlark configuration.
    
    Args:
        ctx: The rule context
    
    Returns:
        The deployment configuration
    """
    return deployment

正如不同的通用編程語言一樣,語法[38] 顯然也略有不同:是否使用大括號(hào),是否允許尾隨逗號(hào),雙引號(hào)與單引號(hào)與無引號(hào),嚴(yán)格嵌套與否,冒號(hào)與等號(hào),是否使用類型名稱,是否在語言內(nèi)部定義模式,是否需要顯式生成語句,額外的關(guān)鍵字或標(biāo)點(diǎn)符號(hào)等等。有些語言的樣板代碼稍多一些,有些則稍少一些。類型安全在每種語言中的工作方式也略有不同。不同的語言會(huì)讓不同的人感覺更熟悉,這取決于他們了解的其他語言。例如,Dhall 可能對熟悉 Haskell 的人來說更熟悉[39]。

在這個(gè)例子中,這些語言并沒有什么顯著的優(yōu)勢。我本可以使用 envsubst。我沒有使用更復(fù)雜的例子,例如圍繞 Deployment 構(gòu)建可重用的函數(shù)或模塊,部分原因是為了保持例子的簡單性,部分原因是我已經(jīng)多次看到這種抽象被削弱[40],并且已經(jīng)看到試圖使配置更可重用適得其反[41] 的嘗試。在任何這些語言中,具有大量參數(shù)的 Kubernetes Deployment 也不會(huì)更簡單。

無論如何,沒有任何配置語言能夠比使用 cdk8s 或 Pulumi 等通用語言的工具更強(qiáng)大。配置語言在 JSON 和 YAML 等數(shù)據(jù)格式與通用語言之間是一種折衷方案。對某些人來說,這是一個(gè)恰到好處的選擇,而對另一些人來說則不然?;蛘咧皇桥渲脧?fù)雜性時(shí)鐘[42]上的一個(gè)停頓點(diǎn)。

其目的是,語言施加的約束應(yīng)該使更容易發(fā)現(xiàn)和防止錯(cuò)誤,并可能使配置更容易閱讀和/或編寫。但是,雖然我已經(jīng)閱讀了許多關(guān)于哪些語言“更好”或“更差”的冗長辯論[43],但它們都是主觀的,并且沒有達(dá)成共識(shí)。我沒有看到任何關(guān)于用不同語言表達(dá)配置生成器的定量益處的研究。如果您知道任何此類研究,請告訴我!

此外,雖然這些語言周圍的生態(tài)系統(tǒng)有時(shí)優(yōu)于模板語言(Pkl 更強(qiáng)調(diào)其集成[44]而不是特定語言特性),但它們實(shí)際上無法與通用語言相比。配置語言可用的文檔、示例、教育內(nèi)容、工具集成、服務(wù)集成等都較少。

原因之一是,所有配置語言的使用范圍都遠(yuǎn)不如 Python 或 Javascript 等流行的編程語言廣泛。其中最流行的語言是 HCL,這當(dāng)然是因?yàn)?Terraform 的流行。但是,我沒有看到 HCL 在 Terraform 生態(tài)系統(tǒng)之外使用,有些人甚至用 YAML 包裝它的用途[45]。就像Helm 的模板語法[46]一樣,并非每個(gè)人都喜歡它,但它通常都能完成工作。

好的,我的觀點(diǎn)是什么?

如果您讀到這里,您可能已經(jīng)猜到我認(rèn)為配置語言并不是解決配置復(fù)雜性的最佳方案。每種語言都有其優(yōu)缺點(diǎn),但沒有任何一種語言能帶來顯著的改變。它們是微優(yōu)化而不是宏優(yōu)化。正如我之前提到的[47]那樣,沒有任何新的配置語言能夠解決IaC 的根本問題[48]。為了取得顯著改進(jìn),我們需要對整體方法進(jìn)行一些宏觀層面的改變。

您是否有我未涉及的喜歡的配置語言?它的優(yōu)勢是什么?您是否發(fā)現(xiàn)使用配置語言與其他表示和方法相比有任何顯著的、可衡量的益處?您是否發(fā)現(xiàn)該語言的任何靜態(tài)分析工具特別有用?您組織中的其他人學(xué)習(xí)該語言是否遇到任何困難?您是否想知道為什么我們到 2025 年仍在手動(dòng)編寫配置文件?

請隨時(shí)在此處回復(fù),或通過LinkedIn[49], X/Twitter[50], 或Bluesky[51]向我發(fā)送消息,我計(jì)劃將此內(nèi)容交叉發(fā)布。

如果您覺得這篇文章有趣,您可能還會(huì)對我的基礎(chǔ)設(shè)施即代碼和聲明式配置系列[52]中的其他文章感興趣。

引用鏈接

[1]?Can Configuration Languages (config DSLs) solve configuration complexity?:https://itnext.io/can-configuration-languages-dsls-solve-configuration-complexity-eee8f124e13a

[2]HCL:https://github.com/hashicorp/hcl

[3]Dhall:https://dhall-lang.org/

[4]Jsonnet:https://jsonnet.org/

[5]Starlark:https://github.com/bazelbuild/starlark

[6]CUE:https://cuelang.org/

[7]Nickel:https://nickel-lang.org/

[8]KCL:https://www.kcl-lang.io/

[9]Pkl:https://pkl-lang.org/

[10]其他:https://github.com/rix0rrr/gcl

[11]15種:https://xkcd.com/927/

[12]YAMLScript:https://yamlscript.org/

[13]KCL 項(xiàng)目的這篇文章:https://blog.stackademic.com/10-ways-for-kubernetes-declarative-configuration-management-3538673fd0b5

[14]比較了 KCL 與許多這些語言:https://www.kcl-lang.io/docs/user_docs/getting-started/intro

[15]確保它們不會(huì)產(chǎn)生副作用:https://sre.google/workbook/configuration-specifics/

[16]根據(jù)自己的喜好塑造語言:https://ruudvanasseldonk.com/2024/a-reasonable-configuration-language

[17]為特定工具創(chuàng)建的:https://www.reddit.com/r/ProgrammingLanguages/comments/gzqsxj/the_future_of_general_purpose_configuration/

[18]Bazel:https://bazel.build/extending/config

[19]Nix 包管理器:https://www.tweag.io/blog/2023-01-24-nix-with-with-nickel/

[20]KusionStack:https://www.kusionstack.io/docs/

[21]使用熟悉的通用語言:/generating-configuration-using-general-purpose-programming-languages-19230a2c2573

[22]CUE:https://cuelang.org/docs/introduction/

[23]Jsonnet:https://jsonnet.org/

[24]通過不允許覆蓋來更容易確定最終值設(shè)置的位置:https://cuelang.org/docs/concept/the-logic-of-cue/#relation-to-inheritance

[25]Dhall 的一個(gè)目標(biāo)是使導(dǎo)入安全:https://dhall-lang.org/

[26]可嵌入的 Python 方言:https://github.com/bazelbuild/starlark/?tab=readme-ov-file#design-principles

[27]JSON 的超集:https://jsonnet.org/articles/design.html

[28]Nickel 中的類型是可選的:https://nickel-lang.org/user-manual/introduction

[29]Pkl:https://www.youtube.com/watch?v=N7zmsHUiTkM

[30]Kubernetes 提供程序:https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/deployment#example-usage

[31]官方示例:https://github.com/dhall-lang/dhall-kubernetes/blob/master/examples/deployment.dhall

[32]更多Kubernetes示例:https://jsonnet.org/articles/kubernetes.html

[33]Kubernetes 教程:https://github.com/cue-labs/cue-by-example/tree/main/003_kubernetes_tutorial#controlling-kubernetes-with-cue

[34]示例:https://github.com/apple/pkl-k8s-examples/tree/main/pkl

[35]示例:https://github.com/tweag/nickel-kubernetes/blob/master/examples/redis-replication-controller.ncl

[36]示例:https://github.com/kcl-lang/examples

[37]示例:https://github.com/cruise-automation/isopod/blob/master/examples/ingress.ipd

[38]語法:https://github.com/lightbend/config/blob/master/HOCON.md#syntax

[39]對熟悉 Haskell 的人來說更熟悉:https://pv.wtf/posts/taming-the-beast#dhall

[40]這種抽象被削弱:/the-tension-between-flexibility-and-simplicity-in-infrastructure-as-code-6cec841e3d16

[41]使配置更可重用適得其反:https://medium.com/itnext/how-software-engineering-instincts-clash-with-infrastructure-as-code-6b18a9cd9cef

[42]配置復(fù)雜性時(shí)鐘:https://mikehadlow.blogspot.com/2012/05/configuration-complexity-clock.html

[43]冗長辯論:https://news.ycombinator.com/item?id=22787332

[44]Pkl 更強(qiáng)調(diào)其集成:https://github.com/apple/pkl/discussions/7

[45]用 YAML 包裝它的用途:https://github.com/AppsFlyer/terra-crust

[46]Helm 的模板語法:/kubernetes-configuration-in-2024-434abc7a5a1b

[47]之前提到的:/fundamental-challenges-with-infrastructure-as-code-imply-the-language-doesnt-matter-41030475c296

[48]IaC 的根本問題:/the-12-anti-factors-of-infrastructure-as-code-acb52fba3ae0

[49]LinkedIn:https://www.linkedin.com/in/bgrant0607/

[50]X/Twitter:https://x.com/bgrant0607

[51]Bluesky:https://bsky.app/profile/bgrant0607.bsky.social

[52]基礎(chǔ)設(shè)施即代碼和聲明式配置系列:https://medium.com/@bgrant0607/list/infrastructure-as-code-and-declarative-configuration-8c441ae74836

責(zé)任編輯:武曉燕 來源: 云云眾生S
相關(guān)推薦

2020-03-04 11:20:22

DSL開發(fā)領(lǐng)域特定語言

2019-08-21 13:24:25

KubernetesHadoop容器

2021-06-07 21:02:44

語言業(yè)務(wù)領(lǐng)域

2013-11-01 13:38:41

程序員編程語言

2012-12-26 10:53:26

2009-03-12 14:31:15

QCon

2017-06-23 08:45:02

存儲(chǔ)技術(shù)復(fù)雜性

2019-05-13 15:47:29

Kubernetes云計(jì)算云復(fù)雜性

2009-01-20 15:23:33

存儲(chǔ)安全密鑰數(shù)據(jù)保護(hù)

2021-04-29 15:15:03

網(wǎng)絡(luò)配置網(wǎng)絡(luò)復(fù)雜性網(wǎng)絡(luò)

2019-07-29 12:35:15

云計(jì)算復(fù)雜性云計(jì)算平臺(tái)

2010-05-27 22:30:08

桌面虛擬化回報(bào)

2019-11-23 23:30:55

Python數(shù)據(jù)結(jié)構(gòu)時(shí)間復(fù)雜性

2016-11-22 09:24:29

大數(shù)據(jù)部署Hadoop

2012-04-10 22:52:58

IBMTivoli云計(jì)算

2023-04-04 08:42:30

IT成本技術(shù)堆

2020-06-15 09:58:23

云計(jì)算云安全數(shù)據(jù)

2012-09-19 13:18:37

復(fù)雜設(shè)計(jì)UI設(shè)計(jì)

2022-06-17 11:04:47

語法分析器GoyaccAST

2018-07-31 14:47:51

Kubernetes開發(fā)應(yīng)用程序
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)