| ▲ | muvlon 6 hours ago |
| If you're interacting with stateful systems (which you usually are with this kind of command), --dry-run can still have a race condition. The tool tells you what it would do in the current situation, you take a look and confirm that that's alright. Then you run it again without --dry-run, in a potentially different situation. That's why I prefer Terraform's approach of having a "plan" mode. It doesn't just tell you what it would do but does so in the form of a plan it can later execute programmatically. Then, if any of the assumptions made during planning have changed, it can abort and roll back. As a nice bonus, this pattern gives a good answer to the problem of having "if dry_run:" sprinkled everywhere: You have to separate the planning and execution in code anyway, so you can make the "just apply immediately" mode simply execute(plan()). |
|
| ▲ | nlehuen 4 hours ago | parent | next [-] |
| And just like that, you find yourself implementing a compiler (specs to plan) and a virtual machine (plan to actions)! |
| |
| ▲ | bbkane 4 minutes ago | parent | next [-] | | I think you're already doing that? The only thing that's added is serializing the plan to a file and then deserializing it to make the changes. | |
| ▲ | lelanthran 4 hours ago | parent | prev [-] | | > And just like that, you find yourself implementing a compiler (specs to plan) and a virtual machine (plan to actions)! Not just any compiler, but a non-typesafe, ad-hoc, informally specified grammar with a bunch of unspecified or under-specified behaviour. Not sure if we can call this a win :-) |
|
|
| ▲ | Jolter 6 hours ago | parent | prev | next [-] |
| I like that idea! For an application like Terraform, Ansible or the like, it seems ideal. For something like in the article, I’m pretty sure a plan mode is overkill though. Planning mode must involve making a domain specific language or data structure of some sort, which the execution mode will interpret and execute. I’m sure it would add a lot of complexity to a reporting tool where data is only collected once per day. |
| |
| ▲ | d7w 2 hours ago | parent | next [-] | | It's not strictly related to the original theme, but I want to mention this. Ansible implementation is okay, but not perfect (plus, this is difficult to implement properly). For cases like file changes, it works, but if you install a package and rely on it later, the --check command will fail. So I am finding myself adding conditions like "is this a --check run?" Ansible is treated as an idempotent tool, which it's not. If I delete a package from the list, then it will pollute the system until I create a set of "tearing-down" jobs. Probably, Nix is a better alternative. | |
| ▲ | muvlon 6 hours ago | parent | prev [-] | | No need to overthink it. In any semi-modern language you can (de)serialize anything to and from JSON, so it's really not that hard. The only thing you need to do is have a representation for the plan in your program. Which I will argue is probably the least error-prone way to implement --dry-run anyway (as opposed to sprinkling branches everywhere). | | |
| ▲ | friendzis 5 hours ago | parent | next [-] | | > you can (de)serialize anything to and from JSON, so it's really not that hard First, it is hard, especially in at least somewhat portable manner. Second, serialization only matters if you cannot (storage, IPC) pass data around in-memory anyway. That's not the problem raised, though. Whatever the backing implementation, the plan, ultimately, consists of some instructions (verbs in parent) over objects (arguments in parent). Serializing instructions any other way than dropping non-portable named references requires one to define execution language, which is not an easy feat. > The only thing you need to do is have a representation for the plan in your program. That "only" is doing lifting heavier than you probably realize. Such representation, which is by the way specified to be executable bidirectionally (roll back capabilities), is a full blown program, so you end up implementing language spec, godegen and execution engines. In cases of relatively simple business models that is going to be the majority of the engineering effort. | | |
| ▲ | michaelmior 3 hours ago | parent [-] | | > First, it is hard, especially in at least somewhat portable manner. I'm curious what portability concerns you've run into with JSON serialization. Unless you need to deal with binary data for some reason, I don't immediately see an issue. > Such representation, which is by the way specified to be executable bidirectionally (roll back capabilities), is a full blown program Of course this depends on the complexity of your problem, but I'd imagine this could be as simple as a few configuration flags for some problems. You have a function to execute the process that takes the configuration and a function to roll back that takes the same configuration. This does tie the representation very closely to the program itself so it doesn't work if you want to be able to change the program and have previously generated "plans" continue to work. |
| |
| ▲ | Jolter 5 hours ago | parent | prev [-] | | Right, but you still have to define every ”verb” your plan will have, their ”arguments”, etc. Not need to write a parser (even Java can serialize/deserialize stuff), as you say, but you have to meta-engineer the tool. Not just script a series of commands. | | |
|
|
|
| ▲ | GeneralMaximus 5 hours ago | parent | prev | next [-] |
| Yes! I'm currently working on a script that modifies a bunch of sensitive files, and this the approach I'm taking to make sure I don't accidentally lose any important data. I've split the process into three parts: 1. Walk the filesystem, capture the current state of the files, and write out a plan to disk. 2. Make sure the state of the files from step 1 has not changed, then execute the plan. Capture the new state of the files. Additionally, log all operations to disk in a journal. 3. Validate that no data was lost or unexpectedly changed using the captured file state from steps 1 and 2. Manually look at the operations log (or dump it into an LLM) to make sure nothing looks off. These three steps can be three separate scripts, or three flags to the same script. |
|
| ▲ | HackerThemAll 24 minutes ago | parent | prev [-] |
| > That's why I prefer Terraform's approach of having a "plan" mode. It doesn't just tell you what it would do but does so in the form of a plan it can later execute programmatically. Then, if any of the assumptions made during planning have changed, it can abort and roll back. And how do you imagine doing that for the "rm" command? |