WEBVTT

00:00:00.700 --> 00:00:05.799
This project turns a small employee CSV into a department summary.

00:00:05.949 --> 00:00:11.090
Engineering has two active employees with a total salary of three hundred.

00:00:11.240 --> 00:00:15.400
Research has one active employee with a total of two hundred.

00:00:15.550 --> 00:00:19.859
A fourth record is inactive and does not belong in this report.

00:00:20.009 --> 00:00:26.708
Before writing code, notice the business definition: we are summarizing active employees only.

00:00:26.858 --> 00:00:33.692
Making that population explicit prevents a technically valid transformation from answering the wrong

00:00:33.692 --> 00:00:34.218
question.

00:00:36.370 --> 00:00:41.405
The command accepts an input CSV path and an output JSON path.

00:00:41.555 --> 00:00:46.355
Like the log project, it checks the argument count before doing any work.

00:00:46.505 --> 00:00:52.926
The fixture includes a header row, department names, numeric salary text, and an active flag.

00:00:53.076 --> 00:00:59.199
The output is JSON because it preserves numbers and objects clearly for another program.

00:00:59.349 --> 00:01:04.767
Start by reading the small fixture yourself and calculating both totals by hand.

00:01:04.917 --> 00:01:11.595
That gives us an independent expected answer instead of trusting the program to validate itself.

00:01:13.740 --> 00:01:21.218
Read lines supplies the CSV parser with an input stream, and the header option gives each record named

00:01:21.218 --> 00:01:21.633
fields.

00:01:21.783 --> 00:01:29.437
The active cell is text, so we compare it with the string true rather than the Boolean true used in our

00:01:29.437 --> 00:01:30.530
JSON API example.

00:01:30.680 --> 00:01:33.539
This distinction comes from the input format.

00:01:33.689 --> 00:01:41.414
Filtering happens before salary conversion because our report only validates and summarizes the active

00:01:41.414 --> 00:01:41.966
population.

00:01:42.116 --> 00:01:49.007
A whole file quality audit would need a separate policy that also examines inactive records.

00:01:51.160 --> 00:01:55.981
Convert each selected salary to a number and reject negative amounts.

00:01:56.131 --> 00:02:00.974
Return a smaller record containing only the fields the summary needs.

00:02:01.124 --> 00:02:07.097
Invalid numeric text produces a value error rather than quietly contributing zero.

00:02:07.247 --> 00:02:12.538
Collect completes this validation stage before the output writing stage begins.

00:02:12.688 --> 00:02:19.793
That separation is helpful: we do not want to publish a report that looks complete after only part of the

00:02:19.793 --> 00:02:20.859
input was accepted.

00:02:21.009 --> 00:02:28.090
The fixture uses simple amounts; production financial calculations need an explicit precision and

00:02:28.090 --> 00:02:29.179
rounding policy.

00:02:31.330 --> 00:02:35.447
Convert the validated list to a Stream and group by department.

00:02:35.597 --> 00:02:42.836
Grouping needs to see the finite input before it can produce the department collections, so it is a

00:02:42.836 --> 00:02:43.640
materializing step.

00:02:43.790 --> 00:02:50.929
Each group contains a key, which is the department name, and values, which is the list of employee

00:02:50.929 --> 00:02:52.515
records in that department.

00:02:52.665 --> 00:02:54.457
Keep those shapes in mind.

00:02:54.607 --> 00:03:02.526
Most confusing pipeline errors come from assuming a stage still receives individual employees when it now

00:03:02.526 --> 00:03:04.506
receives groups of employees.

00:03:06.660 --> 00:03:11.140
For each group, the employee count is the length of its values list.

00:03:11.290 --> 00:03:18.095
To calculate the total, convert that list to a Stream, select salary, and sum the resulting numbers.

00:03:18.245 --> 00:03:22.555
Return one summary object with the department, count, and total.

00:03:22.705 --> 00:03:27.974
We are intentionally deriving both measurements from the same filtered population.

00:03:28.124 --> 00:03:35.411
If you counted employees before filtering but summed after filtering, the report could contain

00:03:35.411 --> 00:03:41.137
inconsistent columns even though every individual operation executed without an error.

00:03:43.290 --> 00:03:49.071
Sort the summaries by department so repeated runs have a stable presentation order.

00:03:49.221 --> 00:03:55.301
Collect the finite summaries, encode readable JSON, and save the destination file.

00:03:55.451 --> 00:04:01.915
Open the result and compare the two departments, counts, and totals with your hand calculation.

00:04:02.065 --> 00:04:05.073
Do not check only that JSON was created.

00:04:05.223 --> 00:04:11.239
A useful test checks the business result, including the exclusion of the inactive record.

00:04:11.389 --> 00:04:17.654
Pretty formatting helps a person inspect the data while preserving a format that another program can

00:04:17.654 --> 00:04:18.045
parse.

00:04:20.200 --> 00:04:23.357
Run the same script with invalid dot CSV.

00:04:23.507 --> 00:04:30.185
Its salary contains the word wrong, so conversion fails and the command exits unsuccessfully.

00:04:30.335 --> 00:04:35.903
The verification driver checks this negative case as well as the successful totals.

00:04:36.053 --> 00:04:42.794
For practice, add an active employee in a new department and an inactive employee in Engineering.

00:04:42.944 --> 00:04:45.205
Predict which count and total change.

00:04:45.355 --> 00:04:46.955
Then rerun the report.

00:04:47.105 --> 00:04:54.554
You have now built a complete transformation with explicit population selection, numeric validation,

00:04:54.554 --> 00:04:59.137
grouping, deterministic output, and a reproducible failure case.

