Locked learning resources

Join us and get access to thousands of tutorials and a community of expert JavaScript developers.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert JavaScript developers.

Unlock This Lesson

Porting the Batch Planner

Porting the Batch Planner

In this lesson, you ported the head roaster’s whole Python planner to JavaScript, line by line, for tonight’s paste of "37.5", then checked the port against Python’s output.

  • The roastery’s order dashboard runs on JavaScript, so the planner moves there and must print the same plan: one wrong line, and tomorrow’s roast starts from the wrong beans or the wrong bill.
  • The docstring becomes a JSDoc block, a comment between /** and */, not a string the program keeps. import math goes, because Math is a global in JavaScript.
  • Each setting keeps its UPPER_SNAKE_CASE name and gains const: Python’s capitals are only a convention, but const refuses any reassignment. The order stays text, as pasted.
  • float() becomes Number(), because JavaScript has one number type. Where float() raises on a paste with a comma, like "37,5", Number() returns NaN, so the port checks with Number.isNaN() on the next line. On a paste like that, console.error() prints a message and process.exit(1) stops the run.
  • In the batches line, // gives way to Math.floor() of a plain division. Here’s the first place a fast port slips: JavaScript has no floor-division operator, and // starts a comment there. Python needs int() because its // on a float gives a float; JavaScript has one number type, so int() drops away.
  • The last batch’s % carries over as it is, because both numbers are positive. math.ceil() becomes Math.ceil(), and the parentheses change nothing.
  • round(x, 2) becomes Math.round(x * 100) / 100. The second slip would be a digits argument: Math.round() has none and rounds to a whole number, so the cost goes to cents and back.
  • The total adds the delivery charge to a number. The third slip would be .toFixed() in this line: it returns a string, and + would join the delivery charge onto it.
  • Template literals have no format specs, so the port builds three formatters once, above the output lines: euros for amounts, percent for shares, and kilos for exactly one decimal, each with its locale named.
  • Each print() becomes console.log() with a template literal. Long lines split in two: Python joins two strings side by side, and JavaScript doesn’t, so + joins the halves. The last batch’s weight uses .toFixed(1), because Python’s spec there has no thousands separator. euros adds the euro sign, so the port’s line drops the one Python writes by hand.
  • node --check reads the file without running it and prints nothing when there’s no syntax error. The port then prints the same four lines as Python: same beans, same bill.

Here’s the Python planner:

Language: Python
"""Plan tomorrow's roast from the evening's big order."""

import math

ORDER_KG_TEXT = "37.5"
WEIGHT_LOSS = 0.15
DRUM_KG = 12
BAG_G = 250
GREEN_PRICE_PER_KG = 7.4
SHIPPING_EUR = 12

order_kg = float(ORDER_KG_TEXT)
green_kg = order_kg / (1 - WEIGHT_LOSS)
full_batches = int(green_kg // DRUM_KG)
last_batch_kg = green_kg % DRUM_KG
bags = math.ceil(order_kg * 1000 / BAG_G)
cost = round(green_kg * GREEN_PRICE_PER_KG, 2)
total = cost + SHIPPING_EUR

print(f"Green beans: {green_kg:,.1f} kg "
      f"(roast loss {WEIGHT_LOSS:.0%})")
print(f"Batches: {full_batches} full + {last_batch_kg:.1f} kg "
      f"({last_batch_kg / DRUM_KG:.0%} of a drum)")
print(f"Bags: {bags}")
print(f"Green coffee: €{total:,.2f} with delivery")

Locked learning resources

Join us and get access to thousands of tutorials and a community of expert JavaScript developers.

Unlock This Lesson

Already a member? Sign-In

Locked learning resources

The full lesson is for members only. Join us and get access to thousands of tutorials and a community of expert JavaScript developers.

Unlock This Lesson

Already a member? Sign-In

00:02 The roastery’s dashboard runs on JavaScript, so the planner moves there and must print the same plan. One wrong line, and tomorrow’s roast starts from the wrong beans or the wrong bill.

00:14 Here’s the whole Python script: a docstring, the import, six settings, the calculation, and four output lines. You’ll port it for tonight’s paste of 37.5 kilos, then compare the outputs line by line.

00:31 The docstring becomes a JSDoc block, a comment between /** and */, not a string the program keeps. The import goes, because Math is a global in JavaScript.

00:45 Each setting keeps its UPPER_SNAKE_CASE name and gains const in front. Python’s capitals are only a convention, but const refuses any reassignment.

00:56 The order stays text, as pasted.

01:01 Python’s float() becomes Number(), because JavaScript has one number type. Where float() raises on a paste with a comma, Number() returns NaN, and the plan would run on.

01:13 So the port checks with Number.isNaN() on the next line. On a paste like that, console.error() prints a message and process.exit(1) stops the run.

01:25 Tonight’s paste converts to a number, so the check lets it through.

01:30 The green beans line gains a const and a camelCase name. In the batches line, // gives way to Math.floor() of a plain division.

01:40 Here’s the first place a fast port slips: JavaScript has no floor-division operator, and // starts a comment there. Python needs int() because its // on a float gives a float.

01:54 JavaScript has one number type, so int() drops away. The last batch’s % carries over, because both numbers are positive. The bags’ math.ceil() turns into Math.ceil(), and the parentheses change nothing.

02:12 Python’s round() with two digits becomes Math.round() of the cost in cents, divided by 100. The second slip would be a digits argument: Math.round() has none and rounds to a whole number, so the cost goes to cents and back.

02:29 The total adds the delivery charge to that number. And the third slip would be .toFixed() in this line: it returns a string, and the + would join the delivery charge onto it.

02:43 Python formats inside its f-strings, but template literals have no format specs. The port builds three formatters once, above the output lines. euros formats an amount as euros, percent shows a share as a whole percentage, and kilos keeps exactly one decimal.

03:03 Each names its locale, so the output doesn’t depend on the machine. Each print() becomes console.log() with a template literal.

03:14 The long lines split in two. JavaScript doesn’t join side-by-side strings the way Python does, so a + joins the halves. The last batch’s weight uses .toFixed(1), because Python’s spec there has no thousands separator.

03:31 The drum share goes through percent, and the bags need no format. euros formats the total, euro sign included, so the port’s line drops the one Python writes by hand.

03:44 node --check reads the file without running it and prints nothing, so there’s no syntax error.

03:52 Python prints four lines. The formatters fold away, bringing the batches, cost and total into view. Which of the port’s lines, if any, will differ from Python’s?

04:05 Your turn: pause the video and predict.

04:13 None of them. The port’s plan matches Python’s, line for line: same beans, same bill.

04:23 A whole script ports line by line: keep each line’s logic, and change only what JavaScript does differently. Check the paste where it’s converted. For Python’s //, math.ceil() and round(), use the Math functions.

04:39 Keep numbers until the output line, where the formatters take over.

04:44 Next up: the exercise, Finish the Batch Planner. You’ll run the planner on the head roaster’s three orders and make both scripts agree.

Become a Member to join the conversation.