Skip to content

Factory Sensors concept exercise #953

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 50 commits into from
Jun 11, 2025
Merged

Conversation

colinleach
Copy link
Contributor

@colinleach colinleach commented Jun 9, 2025

This is what I've got so far. Maybe it's enough?

I've left in the residues of previous attempts in runtests and exemplar. They will all need removing before we merge.

Colin Leach added 30 commits April 2, 2025 15:14
@depial
Copy link
Contributor

depial commented Jun 10, 2025

I can see if I can try to write some instructions and hints to complement this (but that might have to wait for tomorrow).

Of course, if that simply isn't enough in the end, we shouldn't hesitate to pull back and go with a simpler implementation, either without try-catch, or something with just a single block necessary.

@depial
Copy link
Contributor

depial commented Jun 10, 2025

I've realized that we could put the @info "humidity level check passed: $pct_humidity%" and @info "temperature check passed: $temperature °C" from the try clauses as return values for the helper functions. That could likely make the use of try-catch blocks a bit more intuitive/simple, since nothing other than those functions would have to be used in the try clauses.

If we do that, I'd probably rename the functions to something like humiditycheck and temperaturecheck to better match the @info message.

Anyway... Brain is done for the day! :D

@colinleach
Copy link
Contributor Author

colinleach commented Jun 10, 2025

Good suggestions, I'm happy to change tasks 1 & 2 if it helps task 3.

My brain feels like it's done for the month, if not the year.

@depial
Copy link
Contributor

depial commented Jun 11, 2025

Okay, here's an update on what I've got. Let me know if you think this is sufficient, if we should add more instruction/hints, or if we should just simplify Task 4.

Notes:

  • I've added another task in the definition of MachineError
  • I've focused the hints on pushing the student to the two try...catch blocks without a finally clause.
  • Function names have been changed to line up with log messages.
  • Extra code examples have been given for (now) Task 4, including extra white space.

Hinted solution:

function humiditycheck(pct_humidity)
    pct_humidity > 70 && error("humidity level too high: $pct_humidity%")
    @info "humidity level check passed: $pct_humidity%"
end

function temperaturecheck(temperature)
    isnothing(temperature) && throw(ArgumentError("sensor is broken"))
    temperature > 500 && throw(DomainError(temperature))
    @info "temperature check passed: $temperature °C"
end

struct MachineError <: Exception end

function machinemonitor(pct_humidity, temperature)
    errors = 0
    try
        humiditycheck(pct_humidity)
    catch humidity_error
        errors += 1
        @error "humidity level check failed: $pct_humidity%"
    end
    try
        temperaturecheck(temperature)
    catch temp_error
        errors += 1
        temp_error isa ArgumentError ? (@warn "sensor is broken") : (@error "overheating detected: $temperature °C")    
    end
    iszero(errors) || throw(MachineError())
end

Testset:

using Test

include("factory-sensors.jl")

@testset verbose = true "tests" begin
    @testset "1. Monitor the humidity level of the room" begin
        @testset "Passing" begin
            @test_logs (:info, "humidity level check passed: 53%") humiditycheck(53)
        end

        @testset "Failing" begin
            @test_throws ErrorException humiditycheck(80)
            @test_throws "80" humiditycheck(80)
        end       
    end

    @testset "2. Check for overheating" begin
        @testset "Passing" begin
            @test_logs (:info, "temperature check passed: 200 °C") temperaturecheck(200)
        end

        @testset "Failing" begin
            @test_throws ArgumentError temperaturecheck(nothing)
            @test_throws DomainError temperaturecheck(501)
            @test_throws "501" temperaturecheck(501)
        end
    end

    @testset "3. Monitor the machine" begin
        @testset "Passing" begin
            @test_logs (:info, "humidity level check passed: 53%") (:info, "temperature check passed: 200 °C") machinemonitor(53, 200)
        end

        @testset "Failing" begin
            @test_logs (:error, "humidity level check failed: 80%") (:info, "temperature check passed: 220 °C") begin
                @test_throws MachineError machinemonitor(80, 220) 
            end
            @test_logs (:info, "humidity level check passed: 52%") (:warn, "sensor is broken") begin
                @test_throws MachineError machinemonitor(52, nothing)
            end       
            @test_logs (:info, "humidity level check passed: 21%") (:error, "overheating detected: 540 °C") begin
                @test_throws MachineError machinemonitor(21, 540) 
            end
            @test_logs (:error, "humidity level check failed: 100%") (:warn, "sensor is broken") begin
                @test_throws MachineError machinemonitor(100, nothing) 
            end
            @test_logs (:error, "humidity level check failed: 93%") (:error, "overheating detected: 521 °C") begin
                @test_throws MachineError machinemonitor(93, 521)
            end
        end       
    end
end

Instructions

Elena is the new quality manager of a newspaper factory.
As she has just arrived in the company, she has decided to review some of the processes in the factory to see what could be improved.
She found out that technicians are doing a lot of quality checks by hand. She sees there is a good opportunity for automation and asks you, a freelance developer, to develop a piece of software to monitor some of the machines.

1. Check the humidity level of the room

Your first mission is to write a piece of software to monitor the humidity level of the production room. There is already a sensor connected to the software of the company that returns periodically the humidity percentage of the room.

You need to implement a function in the software that will throw an error if the humidity percentage is too high.
If the humidity is at an acceptable level, a info log will be added.
The function should be called humiditycheck and take the humidity percentage as a parameter.

You should halt with an ErrorException (the exact message is not important, but must contain the measured humidity level) if the percentage exceeds 70%.
Otherwise, add an Info log, with the message "humidity level check passed: h%", where h is the humidity percentage.

julia> humiditycheck(60)
[ Info: humidity level check passed: 60%
julia> humiditycheck(100)
ERROR: humidity check failed: 100%

2. Check for overheating

Elena is very pleased with your first assignment and asks you to deal with the monitoring of the machines' temperature.
While chatting with a technician, Greg, you are told that if the temperature of a machine exceeds 500°C, the technicians start worrying about overheating.

The machine is equipped with a sensor that measures its internal temperature.
You should know that the sensor is very sensitive and often breaks.
In this case, the technicians will need to change it.

Your job is to implement a function temperaturecheck that takes the temperature as a parameter and either adds a log if all is well or throws an error if the sensor is broken or if the machine starts overheating.
Knowing that you will later need to react differently depending on the error, you need a mechanism to differentiate the two kinds of errors.

  • If the sensor is broken, the temperature will be nothing.
    In this case, you should halt with an ArgumentError (the message is not important).
  • When the sensor is working, if the temperature exceeds 500°C, you should throw a DomainError that includes the measured temperature.
  • Otherwise, all is well, so add an Info log with the message "temperature check passed: t °C", where t is the temperature.
julia> temperaturecheck(nothing)
ERROR: ArgumentError: sensor is broken

julia> temperaturecheck(800)
ERROR: DomainError with 800:
"overheating detected"

julia> temperaturecheck(500)
[ Info: temperature check passed: 500 °C

3. Define custom error

For the next task, you will need to define a more general, catch-all error.
The implementation details are not important beyond it being an error and the name being MachineError.
You can feel free to include fields and messages as you find helpful.

4. Monitor the machine

Now that your machine can detect errors and you have a custom machine error, you add a wrapper function that can report how everything is working.
Beyond returning the logs from the previous functions, this wrapper will also need to add logs depending on any type(s) of failure(s) that occur.

  • Check the humidity and temperature.
  • If the humidity check throws an ErrorException, an Error log should be added with the message, "humidity level check failed: h%", where h is the humidity percentage.
  • If the temperature check throws an ArgumentError, a Warn log should be added with the message "sensor is broken".
  • If the temperature check throws a DomainError, an Error log should be added with the message, "overheating detected: t °C", where t is the temperature.
  • If either or both of the checks fail, a single MachineError should be thrown after the logs are added.
  • If all is well, only the logs from humiditycheck and temperaturecheck will be added.

Implement a function monitor_the_machine() that takes humidity and temperature as arguments.

julia> machinemonitor(42, 450)
[ Info: humidity level check passed: 42%
[ Info: temperature check passed: 450 °C

julia> machinemonitor(42, 550)
[ Info: humidity level check passed: 42%
┌ Error: overheating detected: 550 °C
└ @ Main # output truncated

Error: MachineError

julia> machinemonitor(82, 521)
┌ Error: humidity level check failed: 82%
└ @ Main # output truncated
┌ Error: overheating detected: 521 °C
└ @ Main # output truncated

Error: MachineError

julia> machinemonitor(42, nothing)
[ Info: humidity level check passed: 42%
┌ Warning: sensor is broken
└ @ Main # output truncated

Error: MachineError

Hints

1. Check the humidity level of the room

  • Simple if...else logic.
  • A ternary operator is good enough.
  • This task uses an error() function, no throw().
  • The @info macro is also needed.
  • Read the Logging section of the introduction to see how to generate log messages.

2. Check for overheating

  • There are two fault conditions to test for.
  • Each needs a throw() if it fails.
  • The @info macro is needed for success.

3. Define custom error

  • See introduction for an example of defining a custom error.
  • Fields and custom print messages are possible but not required.

4. Monitor the machine

  • You can use the humiditycheck and temperaturecheck functions, but this is not strictly necessary.
  • If you use them, you should be able to check independently if both functions throw errors and add the appropriate logs.
  • A variable defined outside of a try...catch block can be updated from inside the block if needed.
  • Reminder: if one check or both checks fail, you only need to throw one MachineError after the logs have been added.

@colinleach
Copy link
Contributor Author

This looks great! I'll go ahead and commit these changes, then make the PR ready for review (when you get chance).

I found some small wording issues, copied from the JS version and carried through all my changes then your changes. For example, "as a parameter" should be "as an argument" for consistency within or syllabus.

replaced with @depial version
replaced with @depial version
replaced with @depial version
replaced with @depial version
@colinleach colinleach marked this pull request as ready for review June 11, 2025 17:50
@colinleach
Copy link
Contributor Author

Given that this is now mostly your exercise, I tend to see you as the author who should get the credit. At the risk of reopening an old argument, are you still refusing this, or can we edit config.json?

@depial
Copy link
Contributor

depial commented Jun 11, 2025

I've added a couple comments on some other small things I've found.

I tend to see you as the author who should get the credit

I don't need credit for stuff unless there's some technical reason for needing to ascribe it, so we can just leave things as they are if you're okay with that.

fixed function names in stubs, added comment about MachineError
@colinleach
Copy link
Contributor Author

Thanks for approving. I'll hold off merge for now, and look through it again later.

I'm not even sure whether the GH-Exercism link is repaired yet.

@depial
Copy link
Contributor

depial commented Jun 11, 2025

I'm not even sure whether the GH-Exercism link is repaired yet.

I just checked and it looks like they've found the cause, but I didn't see if it's actually been resolved.

I was hoping to merge the test sync PR, so I could work on complex-numbers, but I think I've run out of time for today...

added indentation to function skeletons
@colinleach
Copy link
Contributor Author

I was hoping to merge the test sync PR

Apologies, I'd have done this earlier if I'd known it was important to you. FWIW, it's merged and live on Exercism now.

@colinleach
Copy link
Contributor Author

it looks like they've found the cause, but I didn't see if it's actually been resolved

As best I can tell, new merges are succeeding. Things merged yesterday will need to wait for Jeremy to manually resync the tracks with the website.

@depial
Copy link
Contributor

depial commented Jun 11, 2025

Apologies, I'd have done this earlier if I'd known it was important to you.

No worries! It wasn't important. I had quite literally just sat down to look at GH when you started working on this, so it was just as well to be able to use the time I had to help here :)

@colinleach
Copy link
Contributor Author

colinleach commented Jun 11, 2025

I fixed a couple of typos and a formatting glitch. I'll merge when the checks finish, to see what it looks like on the website.

Someone will need to propagate the small typo-fixes to the concept documents, sometime. I'll put a PR in, but it's not urgent.

@colinleach colinleach merged commit b2f91d4 into exercism:main Jun 11, 2025
11 checks passed
@colinleach colinleach deleted the factory-sensors branch June 11, 2025 21:14
@depial
Copy link
Contributor

depial commented Jun 12, 2025

Encouraging news... The first solution by a a student seems to have effectively found the example solution.

@colinleach
Copy link
Contributor Author

That makes me wonder who it is. Seems to be a new user with only 13 rep.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants