Infrastructure rarely exists in a vacuum. Every Terraform configuration interacts with existing infrastructure — VPCs created by another team, AMIs built by an automated pipeline, SSL certificates issued by ACM, Route 53 hosted zones managed by the networking team, and IAM policies managed by the security team. Data sources are Terraform's mechanism for querying and referencing existing infrastructure without managing it — they allow a configuration to read the attributes of resources that Terraform did not create and does not own. Without data sources, engineers must manually copy IDs, ARNs and other identifiers between configurations as hardcoded values, which is brittle (the value becomes stale when the referenced resource is replaced) and duplicative (the same ID is copied into ten different variable files). With data sources, the configuration declares what it needs to know ('find me the VPC named cricket-production') and Terraform queries the AWS API to resolve it at plan time.
The 'depends_on' meta-argument and lifecycle block are surgical tools for controlling Terraform's execution model in situations where the default dependency inference is insufficient. Most production Terraform configurations never need explicit depends_on — the dependency graph is correctly inferred from attribute references, and lifecycle blocks are only needed for specific operational requirements like zero-downtime replacement or protecting irreplaceable resources. Understanding exactly when these tools are needed (and when they indicate a design problem) is the mark of an experienced Terraform engineer. Overuse of depends_on reduces parallelism and makes configurations harder to reason about; proper use of lifecycle blocks protects production infrastructure from operational mistakes that would otherwise be catastrophic.