6 ms·
[disclaimer: CTO at Pulumi so clearly biased :-)] One of the things I really believe is that you can have the best of both worlds here. Pulumi uses imperative
by lukehoban 7y ago
[disclaimer: CTO at Pulumi so clearly biased :-)]
One of the things I really believe is that you can have the best of both worlds here. Pulumi uses imperative programming languages, but is still "declarative". The imperative programs are executed to build up the desired state, which can then be reliably diff'd and previewed, and can be used to enforce manual or automatic checks for correctness. So you get the expressiveness of imperative programs (loops, conditionals, components, packages, versioning, IDE tooling, testing, error checking, etc.), but still the safeguards and reliability of declarative infrastructure-as-code (preview, gated deployments, policy enforcement, etc.).
I also tend to view the perceived benefits of JSON/YAML/HCL "simplicity" as somewhat comparing apples to oranges on a complexity specturm. If you are only managing a dozen resources, it may be that JSON/YAML/HCL are fundamentally simpler. But when you've copy/pasted tens of thousands of lines of YAML around all over your codebase to manage hundreds or thousands of resources, the value of abstraction, reuse, well defined interfaces, and tooling to manage that complexity feels to me essential to the scale of the problem. And that degree of complexity is no longer just something large organizations are dealing with. Modern cloud technologies (serverless, containers, Kubernetes, etc.) are leading to significant increases in the number of cloud resources being managed, and the pace at which those resource are deployed and updated.
Assembly is a "simpler" way to think about programming, but didn't scale as complexity of application software increases. I believe the same is true about JSON/YAML/HCL and cloud infrastructure.
- Boulth 7y agoThanks for the elaborate answer! I wonder if you considered Dhall (https://dhall-lang.org/ https://dhall-lang.org/) that's declarative but at the same time has functions and other convenience factors.
- mixedCase 7y ago> But when you've copy/pasted tens of thousands of lines of YAML around all over your codebase to manage hundreds or thousands of resources, the value of abstraction, reuse, well defined interfaces, and tooling to manage that complexity feels to me essential to the scale of the problem. You're lumping in HCL (and languages like Dhall by extension) with static serialization formats and criticizing them for a characteristic only found in the latter. HCL is programmable and has a fair model for code reusability through modules, state outputs, for-expressions and other kinds of expressions. Add in a proper language with types like Dhall and you have a configuration language where you can apply all the transformations you could want with a much higher safety and robustness floor than a turing-complete language that allows you to make all sorts of messes. It's specially dangerous to have a turing-complete language for configuration once you factor in that the reflex of an inexperienced developer who is more likely to make these messes is to use a tool they're already familiar with even when the tool is actively harmful to their goals, as Pulumi facilitates.
- throwaway894345 7y ago> It's specially dangerous to have a turing-complete language for configuration once you factor in that the reflex of an inexperienced developer who is more likely to make these messes is to use a tool they're already familiar with even when the tool is actively harmful to their goals, as Pulumi facilitates. "Turing complete" is a red herring. You can write a program in Dhall that will continue to run long after we're all dead. But this doesn't happen in practice and/or when it does we notice something is wrong fairly quickly and correct the problem. And because these infra-as-code-and-not-configuration solutions generate configuration, if you do have a loop that doesn't terminate or similar, it's not a problem because your program never deploys any changes. As for making messes, our experienced developers make more of a mess with static configuration because it's fundamentally impossible to manage large static configurations with their inherent repeatable segments that must be kept in sync. The static configuration players try to solve for this by introducing hacky mechanisms for reuse (macros and nested-stacks in CloudFormation, text templates via Helm for Kubernetes, etc), but these fall over very quickly as hacks do.
- mixedCase 7y ago> "Turing complete" is a red herring. You can write a program in Dhall that will continue to run long after we're all dead. It's not the avoidance of the halting problem the reason these languages are better for the task. It's the benefit of having limitations that come with being turing incomplete that prevent us from doing a lot of stupid stuff without realizing it and doing "hacky workarounds" without properly understanding the problem we face. > As for making messes, our experienced developers make more of a mess with static configuration because it's fundamentally impossible to manage large static configurations with their inherent repeatable segments that must be kept in sync. Or don't do static configuration and just use something like Terraform where you can just reference a resource and pass it around.
- throwaway894345 7y ago> It's the benefit of having limitations that come with being turing incomplete that prevent us from doing a lot of stupid stuff without realizing it and doing "hacky workarounds" without properly understanding the problem we face. You'll have to articulate your said benefits to be sure, but I would wager that the principle reason to be turing incomplete is to address the halting problem and that the benefits you're thinking about come from other properties of the language (functional purity, immutability, limitations on I/O, type safety where applicable, etc). Notably, there are lots of hacky workarounds employed in HCL and YAML because people don't understand the problem properly. The problem requires that we can generate arbitrary static configuration from a fixed set of inputs. If your organization is so inept that they keep adding in infinite loops and/or I/O, then by all means, try something like Dhall or Starlark (unfamiliar vs not-type-safe, pick your poison); however, if this is a consistent problem in your organization you probably need to replace your humans because these programs aren't hard to write correctly. > Or don't do static configuration and just use something like Terraform where you can just reference a resource and pass it around. Because this only addresses reuse at the resource level. You can do the same thing in CloudFormation; it's not adequate. For example, not everything is a resource. You ultimately need the ability to generate arbitrary static configuration. Terraform probably has lots of other disparate features that collectively address a good portion of the solution space, but programming languages have a unified concept ("functions") that satisfy the whole solution space and programmers are already familiar with them. Terraform's job should be taking static configs and applying them to infrastructure--let a real programming language generate those configs, or at least offer dynamic configuration language that is designed with a proper understanding of the problem (to use your words).
- je42 7y agoOne my of cases was that I just wanted to extend the workflow of my terraform declaration and add a couple of log statements here and there. I didn't want to write Go to write a plugin for that. With Pulumi - i was able to just sprinkle in a couple of console.log statements and my "extension" was done.
- kitotik 7y agoHand writing JSON/YAML/HCL beyond an initial POC or very, very simple tasks seems like a bad smell. Using whatever language your project already uses to then dump to these formats is a way more sane pattern IMHO.
- tlarkworthy 7y agoI do not doubt Pulumi is more expressive, but that's also my point. It will be interesting to see how it works out. Sbt won Scala mindshare, there is definitely a strong fanbase for expressivity. None of my Terraform projects are 10k lines long. I find it's reusable and at almost the right level of abstraction (Typed templates). I tend to go for a minimum expressivity necessary for DRY. So far I have not found Terraform lacking for a single project, but I have found it lacking for expressing higher order infrastructure (infra code intended for multiple projects). I've never managed a project with thousands of hetrogeneous resources though. I question whether that's really a thing that a single team would do.
- jen20 7y agoI've seen Terraform state files with over 50,000 resources in them. It definitely is something multiple single teams do.
- fierro 7y agoWORD
- cryptonector 7y agoNot only that, but even with a Turing-non-complete language that lets you do useful things (think of Dhall or whatever it's called), chances are pretty good that you can still take forever to terminate if you really try -- you can provably terminate and you can provably not terminate in a lifetime. Granted, no one is going to really do that. And there are good reasons to want provably-terminating programs (e.g., in DTrace, eBPF, ..., because probe actions have to not just terminate, but also run very fast). But for infrastructure deployment? I think Turing complete is fine for that. One idea I've entertained is to use jq as a configuration language and have its output be a JSON text describing a fully-constructed configuration. Yes, jq is Turing complete, but it's so damned convenient!
- dragonsh 7y agoFrom the first look of it will still prefer Guile and Guix deploy or Nix with Nixops. All these systems (like pulumi, terraform, ansible and many more) are not really new or innovative, it’s just re-inventing the same wheel with different names and jumping between declarative and imperative syntax. Guix and Nix both are innovative way to build production, reproducible, secure deployments and platforms without side effects and get rollback and transactions free.