> Tasks are defined and run as if you were running them in the terminal; no more abstractions like BUILD files. But abstractions are a good thing! They let you separate a system into layers, so that things programmed at a higher layer don't need to know all the details of the lower layers. It's the way we separate interface from implementation. Let me give an example from Bazel. Suppose you are compiling some C or C+…
Interfaces are VERY GOOD for migrations.
If you decide that you want to stop using some compiler flag, or maybe use a different compiler, or change your python version, or...
You can right a regex to go over all your shell invocations, change them, then test, or you can do something like:
``` def build_thing(name, srcs, hdrs, migration=False): if migration: ...
build_thing( name = "my_lib", srcs = ["my_lib.cc"], hdrs = ["my_lib.h"], ) ```
You can then manually flip that to test stuff, write a script to flip it for every team, sending out a PR (because your targets can have oncalls) and they can land it, and then at the end you can flip the default and manually add a False to the holdouts.
All this stuff gives you the ability to do hard stuff at scale.