| CSharp/Kata | ||
| Java | ||
| Kotlin | ||
| LICENSE | ||
| README.md | ||
Temperature Kata
A coding kata that focuses on encapsulation and simple design.
An example solution is available.
Thought Process: Designing a Type
Consider this code:
float temperature = 36.7f;
Any problems with this? Discuss with your peers.
Reveal answer
Being roughly the average body temperature (in °C) we might assume that it represents a measurement on the Celsius scale, but we might be misled. Could it be Fahrenheit? Or wouldn't the most appropriate technical temperature scale be Kelvin?
Let's use a clearer name:
float temperatureInCelsius = -300.0f;
That's pretty cold. Any problems with this code?
Reveal answer
Temperatures below roughly -273,15 °C are physically impossible. Let's write some code that tells us whether a temperature is physically possible, since we don't control where the measurements come from:
public class TemperatureUtils {
private static final float CELSIUS_TO_KELVIN_OFFSET = 273.15f;
public static boolean isPhysicallyPossible(float temperatureInCelsius) {
return toKelvin(temperatureInCelsius) >= 0.0f;
}
public static float toKelvin(float temperatureInCelsius) {
return temperatureInCelsius + CELSIUS_TO_KELVIN_OFFSET;
}
}
Now we can easily filter out impossible measurements, if needed. Any problems with this code?
Reveal answer
If it's a simple program that only deals with temperatures, this might be simple enough. But now imagine a more complex domain where not only temperatures, but many more concepts, are represented as a primitive type with public static methods scattered around. At that point, the difference between Java and C becomes negligible.
What are legal/meaningful operations on a temperature? Addition? Multiplication?
Imagine you had an object that represents the concept of a certain temperature:
- It does not imply any specific representation (Celsius, Fahrenheit, Kelvin).
- It hides the internal representation and data type.
- It has a small surface area, allowing only meaningful operations and preventing misuse.
- Conversions are replaced with representations.
- It is easily extensible: There are many more temperature scales (although much rarer in practice).
Requirements
-
Measurements in Celsius, Fahrenheit, and Kelvin are supported (i.e. they might be provided by different (hypothetical) external APIs on those 3 scales).
-
From the caller's perspective, there are no conversions, only representations of the same temperature on the 3 supported scales.
-
Temperatures can be formatted on all 3 supported scales.
-
Immutable: No getters and setters.
Hint
You might be tempted to name some read-only methods
get...(). What's a better naming scheme in this context? Discuss! Remember: We are not accessing internals, but requesting representations. -
Common temperatures (e.g. absolute zero) can be accessed exactly where they would be expected.
Note: You might be tempted to create a (static) class likeTemperatureConstants. What would be a more idiomatic approach? How would you expect the standard library to do it?Hint
We are looking for static factory methods in the
Temperaturetype. Note: We should probably define them as constants, since they are immutable and can thus easily be reused, but that's an implementation detail.PUBLICLY_EXPOSING_THE_CONSTANTSbreaks encapsulation.
Example Values
You can use these values to test your implementation. You can of course look up the formulas, but if you don't fear a challenge, try remapping the scales yourself based on these example values.
I want to try it myself, but I need a hint.
Remap algorithm:
- Normalize the value within the range of the current scale.
- Place it on the target scale by multiplying it with the target scale's range.
- Offset it by the lower of the 2 known values of the target scale.
| Kelvin | Celsius | Fahrenheit | |
|---|---|---|---|
| Absolute zero | 0 K | −273.15 °C | −459.67 °F |
| Freezing point of water | 273.15 K | 0 °C | 32 °F |
| Boiling point of water | 373.1339 K | 99.9839 °C | 211.97102 °F |
© 2023 Raimund Krämer - Use with attribution.
Links to third party sites are included for convenience only and I am not responsible for their contents.