SaveMyCert
Log in
5 of 5 free questions left today·for unlimited practice
Data Ingestion and Transformation

Programming Concepts for AWS Data Engineering: IaC, CI/CD, and Lambda Tuning

13 min readDEA-C01 · Data Ingestion and TransformationUpdated

DEA-C01 expects a data engineer to write code that runs fast, deploy it repeatably, and operate it like software — not just to know service names. That means optimizing transformation code to cut runtime (pushdown, partition pruning, columnar formats, right-sized parallelism), configuring AWS Lambda concurrency and memory correctly, and picking the right language for the job from Python, SQL, Scala, Java, R, and Bash. It also means engineering discipline: version control, automated testing, structured logging, and monitoring with Amazon CloudWatch. Infrastructure as Code turns pipelines into reviewable, repeatable deployments — AWS CloudFormation is the foundation, AWS CDK generates CloudFormation from real programming languages, and AWS SAM streamlines serverless packaging and deployment. CI/CD pipelines then test and promote both code and infrastructure through environments automatically. Finally, the exam checks distributed-computing fundamentals — why Spark partitions work, what shuffles cost — and basic data structures such as trees and graphs. This lesson covers each area at the depth the exam tests, with an IaC comparison table and a worked deployment scenario.

What you’ll learn
  • Optimize ingestion and transformation code to reduce runtime using pushdown, partitioning, and format choices
  • Configure AWS Lambda memory, timeout, reserved and provisioned concurrency for data workloads
  • Compare AWS CloudFormation, AWS CDK, and AWS SAM and choose the right IaC tool for a deployment
  • Design a CI/CD pipeline that tests and deploys data pipeline code and infrastructure across environments
  • Apply software-engineering practices — version control, testing, logging, monitoring — to data pipelines
  • Explain distributed-computing concepts and the data structures that appear in data engineering

Optimizing code to reduce runtime

The fastest way to reduce runtime is to process less data: filter early, read only needed columns, and prune partitions so the engine never touches irrelevant files. Concretely on AWS, that means storing analytics data in a columnar format such as Apache Parquet (readers skip unneeded columns and use embedded statistics to skip row groups), partitioning S3 data by common filter keys like date so queries and Glue jobs read one partition instead of the whole dataset, and using predicate pushdown — Glue pushdown predicates skip listing and reading non-matching partitions entirely, and JDBC sources can push filtering into the database.

Second, match parallelism to the data. Distributed engines like Apache Spark on AWS Glue or Amazon EMR split work across partitions; too few partitions leaves workers idle, while millions of tiny files drown the job in per-file overhead — the notorious small-files problem, fixed by compacting input or writing fewer, larger output files. Avoid operations that force a full shuffle (wide joins, global sorts, high-cardinality groupBys) where a broadcast join or pre-partitioned layout would do, because shuffles move data across the network and dominate job time.

Third, avoid row-at-a-time processing in code. In Python, vectorized operations and batch API calls beat per-record loops; in SQL, set-based statements beat cursors; in Spark, built-in functions beat Python UDFs, which force serialization between the JVM and Python. When an exam question says a job is slow and the dataset is CSV, unpartitioned, or scanned in full, the answer is almost always convert to Parquet, partition, and push filters down — not add more workers first.

Configuring Lambda concurrency and performance

Tune Lambda along two axes: per-invocation resources and fleet-level concurrency. Memory is the single performance dial — CPU and network scale proportionally with the memory setting, so a CPU-bound transformation often finishes disproportionately faster (and sometimes cheaper) at higher memory. Set the timeout to realistic worst-case duration, and remember Lambda has a hard maximum execution time measured in minutes — long transformations belong in AWS Glue or Amazon EMR, not a bigger Lambda.

Concurrency controls how many executions run simultaneously. Reserved concurrency carves out capacity for a function and simultaneously caps it — the standard way to protect a downstream database from being flooded by a burst of S3 events (cap the consumer, let Amazon SQS buffer the backlog). Provisioned concurrency keeps execution environments initialized so latency-sensitive invocations skip cold starts; it costs money while provisioned, so it is for predictable latency requirements, not batch ETL. Unhandled bursts beyond available concurrency are throttled, which is why event-source buffering with SQS plus a dead-letter queue is the resilient ingestion pattern.

Also know the execution-environment facts the guide calls out. Initialization code outside the handler runs once per environment and is reused across warm invocations — put connection setup there. /tmp provides ephemeral scratch space, and for larger or shared file access a Lambda function can mount an Amazon EFS file system, which is the answer when a function needs more working storage than local scratch or must share files across invocations and functions. For stream sources such as Kinesis, per-shard batching and parallelization factor — not memory — govern throughput.

Languages and frameworks for data engineering

Pick the language the runtime favors, not a personal favorite. Python is the default: Glue ETL scripts (PySpark), Lambda functions, Airflow DAGs on Amazon MWAA, and AWS SDK (boto3) automation are all Python-first, and libraries such as pandas and AWS SDK for pandas cover small-to-medium transformation. SQL is the second universal language — Amazon Athena and Amazon Redshift are SQL engines, Spark SQL expresses most Glue transformations, and pushing transformation into SQL (ELT) often beats hand-written code for both clarity and performance.

Scala and Java matter because Apache Spark is JVM-native: Glue and EMR both run Scala Spark jobs, and JVM code avoids the Python-UDF serialization penalty, so performance-critical Spark logic is sometimes rewritten in Scala. Java also appears in Kafka ecosystems around Amazon MSK and in Kinesis consumer libraries. R is a statistics and analysis language you will meet in analytics teams (and in Amazon EMR via Spark), not a pipeline-orchestration language. Bash (and PowerShell) script the AWS CLI for operational glue: EMR bootstrap actions, container entrypoints, and CI/CD steps.

The exam angle is fit-for-purpose selection. A question describing a Glue streaming job or a Lambda transformation expects Python; one emphasizing maximum Spark performance for complex UDF-heavy logic hints at Scala; one about ad hoc analysis over S3 data expects SQL via Athena; one about automating an AWS CLI sequence expects Bash. Framework choices follow the same logic — Spark for distributed batch, pandas for single-node work that fits in memory, and SQL engines when the transformation is expressible as queries.

Software-engineering best practices for pipelines

Treat pipeline code like production software: versioned, tested, logged, and monitored. Version control everything — Glue scripts, Lambda handlers, Airflow DAGs, SQL, and the IaC templates that deploy them — in Git (AWS-side hosting or GitHub), with branch-based review so changes to production pipelines are inspected before merge. Version control is also the foundation for CI/CD and for rollback when a deployment breaks.

Testing for data pipelines has layers: unit tests for transformation functions (pure logic, run locally in CI), integration tests that run a job against a small representative dataset in a dev environment, and data-quality checks inside the pipeline — AWS Glue Data Quality evaluates rules (completeness, uniqueness, freshness) and can fail a job or raise alerts when data violates them, catching upstream problems before they propagate to consumers.

Logging and monitoring center on Amazon CloudWatch. Lambda and Glue emit logs to CloudWatch Logs — make them structured (JSON) so CloudWatch Logs Insights can query them, and log record counts and durations at stage boundaries so failures are diagnosable. Metrics and alarms cover the operational questions: Glue job failures and duration, Lambda errors and throttles, Step Functions executions failed, SQS queue depth and message age — each alarming to an Amazon SNS topic. AWS X-Ray traces requests across Lambda and API-fronted services when you need to find where latency lives. The exam pattern: a pipeline fails silently or degrades — the correct answer adds CloudWatch alarms on failure metrics with SNS notification, not manual log checking.

Infrastructure as Code: CloudFormation, CDK, and SAM

All three tools deploy through the same engine — AWS CloudFormation — so the choice is about authoring experience, and the comparison below is the decision the exam tests.

DimensionAWS CloudFormationAWS CDKAWS SAM
AuthoringDeclarative YAML or JSON templatesReal code — Python, TypeScript, Java, and more — that synthesizes CloudFormationSimplified YAML: CloudFormation plus serverless-focused transform and resource types
AbstractionLowest: every resource and property spelled outHighest: constructs bundle resources with sensible defaults; loops, conditionals, reuse via packagesModerate: concise shorthand for Lambda functions, APIs, DynamoDB tables, Step Functions
ScopeAll AWS resource typesAll AWS resource types (falls back to low-level constructs)Serverless applications; other resources via embedded plain CloudFormation
ToolingConsole, CLI, change sets, drift detection, StackSets for multi-accountcdk synth, cdk diff, cdk deploy; unit-testable infrastructuresam build, sam local invoke for local Lambda testing, sam deploy; CI/CD-friendly packaging
Best fitTeams standardized on declarative templates; governance and StackSetsDeveloper teams wanting typed, reusable, logic-driven infrastructurePackaging and deploying serverless pipelines: Lambda, Step Functions, DynamoDB

Why IaC at all: repeatable resource deployment. The same template creates identical dev, test, and prod stacks; changes are code-reviewed and diffed (change sets, cdk diff) before execution; a failed deployment rolls back; and drift detection reveals out-of-band console edits. When a question says an environment must be recreated identically in another account or Region, the answer is an IaC template — never manual console steps. When it says "package and deploy a serverless data pipeline of Lambda functions, Step Functions, and DynamoDB tables," the guide's named answer is AWS SAM; when it says "define infrastructure in Python with reusable components," it is CDK.

CI/CD for data pipelines

CI/CD automates the path from commit to production: continuous integration builds and tests every change, and continuous delivery deploys it through environments with gates. On AWS the reference toolchain is a Git repository feeding AWS CodePipeline, with AWS CodeBuild running build and test stages and deployment executed via CloudFormation, cdk deploy, or sam deploy — though the concepts transfer to GitHub Actions and similar tools.

A data-pipeline CI/CD flow has distinctive stages. CI: on each commit, run linting and unit tests on transformation logic, synthesize the IaC (catching template errors early), and package artifacts — a Lambda bundle, a Glue script uploaded to S3, a Docker image to Amazon ECR. Deploy to a test environment: stand up or update the stack, then run the pipeline against representative sample data and assert on the output — row counts, schema, data-quality rules. Promote to production: after automated checks (and often a manual approval gate), deploy the same artifacts with production parameters. Deploying code and infrastructure together from the same repository keeps them in lockstep — a Glue job and the IAM role it needs change in one reviewed commit.

Two practices distinguish good answers. First, environment parity through parameterization: one template, per-environment parameters (bucket names, connection secrets from AWS Secrets Manager), so test genuinely rehearses prod. Second, safe rollout: CloudFormation rollback on failure, and for Lambda, versions with aliases enabling gradual traffic shifting. The exam contrast is manual-versus-automated: any scenario where engineers copy scripts to S3 by hand or click the console for each release is answered by a CI/CD pipeline with automated testing and IaC-driven deployment.

Distributed computing, data structures, and algorithms

Distributed computing means splitting one job across many machines that work in parallel and combine results — the model behind Apache Spark on AWS Glue and Amazon EMR. Data is divided into partitions processed independently by executors; operations that stay within a partition (map, filter) are cheap and scale linearly, while operations that must regroup data across machines (join, groupBy, sort) trigger a shuffle — network movement that is the usual bottleneck. Two practical consequences the exam tests: data skew, where one oversized partition key makes a single executor the straggler that delays the whole job, and the trade-off that distributed engines have startup and coordination overhead, so small datasets run faster on a single node (pandas, or a Lambda function) than on a cluster.

The Spark model is resilient by design: work is expressed as a DAG of transformations, and lost partitions are recomputed from lineage rather than restarting the job — pair that with checkpointing for long streaming jobs. Scaling out (more nodes) handles bigger data; scaling up (bigger nodes) helps memory-hungry tasks; neither fixes a skewed key or an unnecessary shuffle.

Data structures appear at recognition depth. Tree structures underpin indexes and hierarchies — B-tree indexes in relational stores, and sort-based pruning in columnar systems. Graph structures model entities and relationships (nodes and edges) — the natural fit for lineage tracking, dependency DAGs in orchestration, and relationship-heavy datasets. Hash structures give constant-time key lookup, the idea behind key-value access in Amazon DynamoDB and hash-partitioning of data across shards. Know which structure fits which access pattern; the exam does not ask you to implement them.

Scenario: shipping a serverless pipeline properly

Scenario: your team hand-built a pipeline in the console — an S3-triggered Lambda function validates arriving files, a Step Functions state machine runs a Glue job, results land in a DynamoDB table. It works in one account, but management requires identical dev and prod environments, reviewed changes, automated tests before release, and faster Lambda processing. What do you change?

Step 1 — codify. Define the whole stack — the Lambda function, state machine, Glue job, DynamoDB table, IAM roles, and the S3 event wiring — in AWS SAM (serverless-centric, and sam local invoke lets developers test the Lambda handler locally before pushing). Store the template and all code in Git. The console-built originals are replaced by deployed stacks, eliminating drift between environments by construction.

Step 2 — automate. A CodePipeline triggered on merge runs CodeBuild: unit tests on the validation logic, sam build, deploy to the dev stack, then an integration test that drops a sample file into the dev bucket and asserts the DynamoDB output. A manual approval gates sam deploy to prod with production parameters.

Step 3 — tune. Profiling shows the Lambda validation is CPU-bound: raising memory raises CPU proportionally, cutting duration enough that cost barely moves. Reserved concurrency caps the function so a burst of thousands of files cannot overwhelm the downstream Glue trigger path; the S3 events flow through an SQS queue with a dead-letter queue so failures are buffered and inspectable, not lost.

Every choice maps to a Task 1.4 skill: IaC for repeatable deployment, SAM for serverless packaging, CI/CD with testing, and Lambda concurrency and performance configuration.

Tip. Expect scenario questions on why a job is slow — with answers built from Parquet conversion, partitioning, predicate pushdown, and shuffle or small-file fixes — and on Lambda tuning, especially memory-to-CPU scaling and reserved versus provisioned concurrency. IaC questions hinge on choosing CloudFormation, CDK, or SAM for a described team and workload, with SAM tied to packaging serverless pipelines. CI/CD, structured logging with CloudWatch alarms to SNS, and recognizing distributed-computing costs like shuffles and data skew round out Task 1.4's coverage.

Key takeaways
  • Reduce runtime by processing less data first: Parquet over CSV, partitioned S3 layouts, predicate pushdown, and fixing the small-files problem — before adding workers.
  • Lambda memory scales CPU and network proportionally; reserved concurrency caps a function to protect downstream systems, and provisioned concurrency pre-warms environments for latency-sensitive work.
  • Long or heavy transformations belong in Glue or EMR, not Lambda — Lambda's execution time is capped at minutes; mount Amazon EFS when a function needs more or shared file storage.
  • CloudFormation, CDK, and SAM all deploy via CloudFormation: templates are the declarative base, CDK authors infrastructure in real programming languages, and SAM is the shorthand plus local-testing toolkit for serverless pipelines.
  • CI/CD for data pipelines versions code and infrastructure together, runs unit and data-quality tests automatically, deploys through parameterized identical environments, and replaces every manual console release.
  • In distributed computing, shuffles and data skew — not raw data size — are the usual bottlenecks; small datasets are faster on a single node than a cluster.
  • Python and SQL are the default data-engineering languages on AWS; Scala/Java serve JVM-native Spark performance, and Bash scripts the CLI for operational glue.
  • Monitor pipelines with structured logs in CloudWatch, alarms on failure and throttle metrics publishing to SNS, and Glue Data Quality rules that fail jobs on bad data.

Frequently asked questions

How does Lambda memory affect performance and cost?

Memory is Lambda's only resource dial: CPU and network allocation scale proportionally with it. A CPU-bound function given more memory often finishes so much faster that total cost (billed on memory times duration) stays flat or drops. When a Lambda transformation is slow, increasing memory is the first tuning step; if the work still approaches Lambda's hard timeout, move it to AWS Glue or Amazon EMR.

What is the difference between reserved and provisioned concurrency?

Reserved concurrency guarantees a function a slice of account concurrency and simultaneously caps it at that number — used to protect downstream systems from bursts or to ensure a critical function is never starved. Provisioned concurrency keeps execution environments initialized ahead of time to eliminate cold-start latency, and it bills while provisioned. Reserved is a limit and guarantee; provisioned is pre-warming.

When should I use AWS SAM instead of plain CloudFormation or CDK?

Use SAM when the deliverable is a serverless application — Lambda functions, Step Functions state machines, API front ends, DynamoDB tables. Its transform makes those resources concise, and its CLI adds what serverless teams need most: sam build for packaging and sam local invoke for testing functions locally. Choose CDK when you want infrastructure in a real programming language with reusable constructs; plain CloudFormation when the team standardizes on declarative templates.

Why is a distributed Spark job sometimes slower than a single-node script?

Distributed engines pay startup and coordination overhead — provisioning executors, scheduling tasks, and shuffling data across the network. For datasets that fit comfortably on one machine, pandas or a Lambda function skips all of that and wins. Clusters earn their overhead only when data volume or compute genuinely exceeds a single node, and even then skewed keys or unnecessary shuffles can erase the gain.

What belongs in a CI/CD pipeline for a data pipeline?

On commit: lint, unit-test the transformation logic, synthesize and validate the IaC, and package artifacts. Then deploy to a test environment and run an integration test on representative sample data, asserting on output counts, schema, and data-quality rules. Finally, promote the same artifacts to production — typically behind an approval gate — with per-environment parameters, so test genuinely rehearses prod and rollback is automatic on failure.

What do I actually need to know about data structures for DEA-C01?

Recognition, not implementation. Trees back database indexes and hierarchical data (B-tree indexes, sorted pruning). Graphs model nodes and edges — data lineage, orchestration DAGs, relationship-heavy data. Hash structures give constant-time key lookup, the principle behind DynamoDB key access and hash partitioning. Expect to match a structure to an access pattern or use case, not to write algorithms.

Test yourself on this topic
Practice questions with full explanations.
Practice now

Sign up free to mark lessons complete, bookmark topics and track your exam readiness.