Skip to content
SparkTime, home
Off-Campus Placements With AI
Lessons
1 · Reality Check and Your Search Plan
2 · Building Credibility From Zero
3 · Resume and LinkedIn
4 · Finding Jobs Before the Crowd
5 · Applications and Referrals
6 · Online Assessments and DSA
7 · Company Research for Interviews
8 · Technical Interview Rounds
9 · Behavioral and HR Rounds
10 · Offers, Negotiation and Joining
11 · Rejection, Diagnosis and Momentum
Lesson 10 of 44

Lesson 10 · Building Credibility From Zero

Honest Numbers: Measuring and Quantifying Student Projects

Resume advice says to quantify everything, but a student project has no revenue and few users. This article shows which numbers you can legitimately measure (speed, load, correctness, coverage, scale, time saved), how to measure them so they survive questions, how to summarise them with medians and percentiles, and how to turn them into resume bullets with AI without inventing a single figure.

On this page

Key takeaways

  • You can measure real numbers on a student project: response time, load handled, query speed-ups, correctness, test coverage, data size and time saved.
  • A number is only useful if you can say how you measured it: the tool, the conditions, the sample size and the summary statistic.
  • Report medians and 95th percentiles rather than averages or best runs, and test load on your own machine, not on someone else's free servers.
  • Turn measurements into bullets with the X-Y-Z pattern: what you achieved, measured how, by doing what.
  • Let AI shape bullets only from numbers you give it, and remove anything it adds. Never invent users, traffic or percentages.

"Quantify your achievements" is the most repeated resume advice there is. For a fresher it creates a trap. Your project has no revenue, a handful of users and no production traffic. So people reach for numbers that sound good: "improved performance by 60%", "handled 10,000 users", "99.9% uptime". The interviewer asks one question ("how did you measure that?") and the number collapses, taking your credibility with it.

There is a better way. Student projects can produce many real numbers. You just have to measure them on purpose.

What you will learn

#
  • Which kinds of numbers a student project can honestly report.
  • How to measure each one so that it survives a follow-up question.
  • Why medians and percentiles beat averages, with a short program.
  • The X-Y-Z pattern for turning a measurement into a resume bullet.
  • How to use AI to shape bullets without letting it add numbers.

Numbers you can measure

#

Kind of number

Example

How to measure it

Speed

Median response time of an endpoint

Time repeated requests with a load-testing tool or a script

Speed-up

Query time before and after an index

Run the query many times before and after; use the database's query plan tools

Load

Requests per second handled at an acceptable latency on your machine

A load-testing tool (such as k6, JMeter or hey) against a local copy

Correctness

Tests passing, including failure cases

Your test runner's report

Coverage

Percentage of lines or branches exercised by tests

A coverage tool (JaCoCo for Java, coverage.py for Python, built-in tools for JavaScript)

Accuracy

Categoriser correct on a labelled sample

Label a sample by hand, compare the output

Scale of data

Rows processed, file sizes handled

Count them

Time saved

Minutes a task took before and after your tool

Time yourself doing the task both ways, several times

Reliability

Duplicate payments prevented under simulated failures

A test that injects failures and checks the outcome

Adoption

People who actually used it

Only real, countable use: a club that used it for an event, classmates who signed up

What you cannot honestly report: users you do not have, uptime you never monitored, "scalability" you never tested, or a percentage improvement against a baseline you never measured.

Measuring so the number survives questions

#

Every number needs four things you can say out loud:

  1. The tool. "I used k6", "I used EXPLAIN ANALYZE in PostgreSQL", "I timed it with a script".
  2. The conditions. Your laptop or a server, what data, which endpoint, how many concurrent users.
  3. The sample size. One run tells you almost nothing. Twenty or more requests tell you something.
  4. The summary statistic. Median, 95th percentile, or a count.

"Median response time of 15 ms over 200 requests on my laptop, with 10,000 seeded rows" survives any follow-up question. "Fast" does not.

Why medians and percentiles

#

Response times have outliers: the first request after start-up, a garbage-collection pause, a background task. One slow outlier drags an average up a lot, and a single best run is just luck. The median (the middle value) tells you what a typical request experiences. The 95th percentile (p95) tells you what the slowest one-in-twenty experiences, which is what users notice.

This program summarises recorded response times. The data is a sample for illustration: 20 requests before and after adding a database index.

Python
# File: latency_summary.py# Summarise response times you recorded (in milliseconds).# The two lists are sample data for illustration: 20 requests each,# measured before and after adding a database index.import statisticsbefore = [412, 398, 405, 420, 391, 388, 1450, 402, 415, 399,          410, 395, 401, 407, 390, 404, 396, 409, 1380, 403]after = [16, 14, 15, 17, 13, 15, 210, 14, 16, 15,         15, 14, 13, 16, 15, 14, 15, 17, 198, 16]def percentile(values, p):    """Nearest-rank percentile: the value below which p% of samples fall."""    ordered = sorted(values)    rank = max(1, round(p / 100 * len(ordered)))    return ordered[rank - 1]def summary(name, values):    print(f"{name:<7} n={len(values)}  median={statistics.median(values):.0f} ms  "          f"p95={percentile(values, 95)} ms  mean={statistics.mean(values):.0f} ms")summary("before", before)summary("after", after)change = 1 - statistics.median(after) / statistics.median(before)print(f"median improvement: {change:.0%}")
Code
before  n=20  median=404 ms  p95=1380 ms  mean=504 msafter   n=20  median=15 ms  p95=198 ms  mean=34 msmedian improvement: 96%

Look at the "before" line: two slow outliers push the mean to 504 ms although a typical request took about 404 ms. The median is the honest headline; the p95 shows the outliers are still there after the change (198 ms), which is a good follow-up topic in an interview: "What causes the slow tail?"

Load testing safely

#

A load test sends many requests at once to see how your service behaves. Two rules:

  • Test your own machine or your own paid resources. Sending heavy load to a free hosting tier can break the provider's terms and get your account suspended, and it measures their throttling, not your code. Run the service locally (or in a container with fixed CPU and memory) and load test that.
  • Report the conditions. "On a laptop with 8 GB RAM, the API served 150 requests per second with a p95 under 200 ms at 50 concurrent users" is honest. "Handles 10,000 users" is not.

An illustrative fragment of a k6 test script, to show what one looks like (k6 scripts are written in JavaScript):

JavaScript
import http from "k6/http";export const options = { vus: 50, duration: "60s" };export default function () {  http.get("http://localhost:8080/api/events?page=1");}

The tool prints the median, p95 and requests per second at the end. Copy that summary, with the conditions, into your README.

Database speed-ups

#

For a query you improved (an index, a rewritten join), use your database's query-plan tool before and after. In PostgreSQL, EXPLAIN ANALYZE runs the query and shows the time and whether an index was used. Seed enough data to make the difference real: on 50 rows, everything is fast. Run each version several times and report the median.

Accuracy and correctness

#

For anything that classifies or extracts (a transaction categoriser, a resume parser), label a sample by hand, say 100 items, and count how many your program gets right. Report it with the sample: "92 of 100 hand-labelled transactions categorised correctly". Also note what it gets wrong; it makes an excellent interview discussion.

GitHub traffic, carefully

#

GitHub shows repository owners recent traffic (views and clones) under the repository's Insights. Use these numbers with care. Clones include automated tools, views include your own visits, and the window is short. "Viewed by 400 people" is rarely accurate; if you mention traffic at all, say exactly what the page shows, or leave it out. Real usage is a stronger signal than page views.

From measurement to resume bullet: the X-Y-Z pattern

#

A widely used pattern for achievement bullets is: accomplished X, as measured by Y, by doing Z.

  • X is the outcome.
  • Y is the number, with enough context to be checkable.
  • Z is what you did, which is the part that shows skill.

Weak bullet

X-Y-Z bullet

Improved search performance

Cut median search latency from 404 ms to 15 ms (200 requests, 10,000 rows) by adding a composite index on title and date

Built a reliable payment service

Prevented duplicate charges in all 12 simulated failure scenarios by enforcing idempotency keys with a unique constraint

Wrote tests

Raised branch coverage of the booking module from 41% to 86% with 34 tests for cancellation and overbooking cases

Made a useful tool

Reduced weekly photo sorting from about 40 minutes to 2 with a CLI that renames 1,000+ files by capture date

If a bullet has no honest number, use impact without a number: "Made booking cancellations safe to retry, so a timeout no longer creates duplicate bookings." That is far better than an invented percentage.

Using AI to shape bullets, not to invent them

#

Assistants are good at tightening wording and very willing to add impressive figures. Give it your numbers, forbid additions, and check the output.

Code
Turn these measured facts into 3 or 4 resume bullets using the pattern"accomplished X, as measured by Y, by doing Z". Rules:- Use ONLY the numbers below, exactly as given. Do not round them up,  combine them into new percentages, or add any number.- If a fact has no number, write an impact bullet without a number.- Under 25 words each. Start with a strong past-tense verb.- After the bullets, list any word you used that I might not be able to defend  in an interview (for example "scalable", "robust").Facts:- Search endpoint: median 404 ms before, 15 ms after a composite index on  (title, event_date); 200 requests; 10,000 seeded rows; my laptop.- 34 tests added; branch coverage of booking module 41% to 86% (JaCoCo).- Cancellation endpoint is idempotent: retrying with the same key returns  the original result.

How to check it: compare every number in the output against your facts. If the assistant wrote "a 96% reduction", it calculated a new figure: fine if it is correct and you can explain it, but check the arithmetic. If it wrote "for thousands of users", delete it.

Measure before every interview

#

Numbers go stale as you change your code. Before an interview, spend half an hour re-running your main measurements and checking that the README and resume match. If an interviewer opens your repository during the call, your numbers should be reproducible from it.

Common mistakes

#
  • Averages from a handful of runs, which outliers and luck distort.
  • Percentages without a baseline. "60% faster" than what, measured how?
  • Load testing someone else's free servers.
  • Counting page views as users.
  • Accepting numbers an assistant added. If you did not measure it, it does not go in.

Exercises

#

Exercise 1

Which numbers are honest?

#

For each claim, say whether it is defensible and what you would need to know or change: (a) "Handles 1 million requests per day" (one load test at 20 requests per second for one minute on a laptop); (b) "Used by 300 students" (a college club used it to register 300 people for one event); (c) "Improved performance by 70%" (felt faster after a change); (d) "92% accuracy" (on 25 items you labelled).

Exercise 2: Compute and interpret

#

Ten response times in ms: 30, 32, 29, 31, 400, 33, 30, 28, 31, 32. Give the median, the mean, and which you would report, and why. What would you investigate?

Exercise 3: Write X-Y-Z bullets

#

Turn these facts into bullets: (a) a CSV import that took 95 seconds for 50,000 rows now takes 6 seconds after switching to batch inserts of 1,000 rows (median of 5 runs); (b) a URL shortener with 27 tests covering collisions, expiry and invalid URLs; (c) a Telegram bot that reminds your hostel about mess timings, used daily by 60 students for a semester.

Exercise 4: Measure one thing

#

Pick one endpoint, query or task in your project. Measure it properly (tool, conditions, at least 20 samples, median and p95), write the result in your README with the conditions, and write one X-Y-Z bullet from it.

Show solutionHide solution

(a) Not defensible as written. 20 requests per second for one minute is 1,200 requests. Multiplying it into "1 million a day" assumes it could sustain that load all day, which you never tested. Honest version: "Served 20 requests per second with a p95 of [x] ms on a laptop (1-minute k6 test)."

(b) Defensible, with context: "Used by a college club to register 300 participants for [event]." That is real adoption. Do not stretch it into "300 active users".

(c) Not defensible. "Felt faster" is not a measurement. Measure before and after (you can often check out the old version from Git) and report the median.

(d) Weak. 25 items is a small sample; one more error changes the figure by 4 points. Label more items (100 or more) or report it plainly: "23 of 25 hand-labelled samples correct".

Exercise 2

Show solutionHide solution

Sorted: 28, 29, 30, 30, 31, 31, 32, 32, 33, 400.

  • Median: the average of the 5th and 6th values, (31 + 31) / 2 = 31 ms.
  • Mean: the sum is 676, so 676 / 10 = 67.6 ms.

Report the median (31 ms) as the typical response time, and mention the outlier. The mean is more than twice the typical value because of one request.

Investigate the 400 ms request: is it the first request after start-up (a cold start, class loading, connection pool creation)? Does it repeat at regular intervals (garbage collection, a scheduled task)? Run more samples to see how often it happens; that tells you whether it shows up in the p95.

Exercise 3

Show solutionHide solution

(a) "Cut import time for 50,000-row CSV files from 95 s to 6 s (median of 5 runs) by switching to batch inserts of 1,000 rows."

(b) "Built a URL shortener with 27 automated tests covering code collisions, link expiry and invalid input." There is no performance number, and none is needed; the tests are the evidence.

(c) "Built a Telegram reminder bot for hostel mess timings, used daily by 60 students for a full semester." Real, countable adoption over time.

Each bullet passes the Follow-Up Test: you can explain how you got every number.

Exercise 4

Show solutionHide solution

A good result in your README looks like this:

Code
## ResultsSearch endpoint (GET /api/events?q=...), measured with k6 on my laptop(Ryzen 5, 16 GB RAM), PostgreSQL 16 locally, 10,000 seeded events,200 sequential requests:- Before composite index on (title, event_date): median 404 ms, p95 1380 ms- After: median 15 ms, p95 198 msSlow tail still under investigation (likely first-request warm-up).

And a bullet: "Cut median search latency from 404 ms to 15 ms (200 requests, 10,000 rows) by adding a composite index on title and date."

If you cannot reproduce your own numbers a week later, your conditions were not written down precisely enough.

Where to go next

#

Keep reading

More in Career →
  • Guide · Career

    Improve Your Resume and Profile with AI, Honestly

  • Guide · Career

    Interview Preparation and Mock Interviews with AI

  • Guide · Career

    A LinkedIn Profile That Gets Recruiter Messages