Burgundy Beef recipe (Bœuf Bourguignon)

My lazy-ish version of Burgundy beef, based on a recipe from my 1998 Petit Larousse de la Cuisine, which I brought with me when I moved to Australia. Sorry if I’m using the incorrect terminology, or explaining obvious things: I’m not a chef or even a good cook!

Ingredients, preparation:

  • 3 carrots, cut in slices less than 1cm.
  • 2 onions, cut in smallish slices (shape doesn’t matter, they will melt).
  • 1.2 kg beef (“casserole” or “gravy” works), diced less than 4cm per side. I also like to remove excess fat and yucky bits!
  • 200 g smoked bacon or speck, without rind, cut in strips.
  • 2 tbsp oil.
  • 2 tbsp plain flour.
  • 0.5 L veal or beef stock (in carton, or stock cubes melted in hot water), veg or chicken stock is fine too if that’s what you have.
  • 0.6 L red Burgundy wine (or other Pinot Noir).
  • 1 clove garlic, crushed or chopped very finely.
  • Bouquet garni (supermarkets should have it in teabag form, in the spice section; it’s a mix of thyme, bay leaf, parsley, and some other herbs).
  • salt, pepper.
  • (optional) Mushrooms, may be added near the end of cooking, but I don’t want to talk about it anymore — how can anyone eat fungus*? 🤢

Directions:

  1. Put the oil in a big pot (that can hold at least 3 L), high heat.
  2. When oil is hot (put a small bit of bacon, it should start sizzling), add bacon.
  3. Cook for a few minutes, stirring frequently, to taste (not crispy for me).
  4. Remove bacon, but keep the oil&juices in the pot.
  5. Add beef, cook for a few minutes, stirring to make sure all sides become brown. You may add a bit of salt, but not too much (bacon and later reduction could make it over-salty!)
  6. Add carrots and onions, stir, and cook for a few minutes more. Onions should become softer.
  7. (Optional) Discard juices.
  8. Sprinkle with flour, stir and let it cook a bit more.
  9. Add cooked bacon, stock, wine, garlic, bouquet garni, pepper. There should be enough liquid to cover everything. Stir.
  10. When it start to bubble, reduce heat to keep it simmering gently — not too hot, or some meat will stick to the bottom. Cover pot.
  11. Let it simmer for at least 2 hours, the more the better, overnight is the best! Regularly stir and adjust heat if needed. Enjoy the aromas floating around the whole house!
  12. Uncover, remove bouquet garni, increase the heat a bit for a stronger bubbling, but not full-on boil. Let it reduce (by evaporation – make sure your hood extractor fan is on), this may take 30-60 minutes. Try reducing by about 20% first, the sauce should feel a bit thicker, it should coat a spoon. If not sure, just try it like that in a meal, you can reduce more if you prefer it thicker.
  13. If needed, season with salt and pepper to taste.
  14. Serve with your choice of cooked vegetables. I think it goes best with mashed potato or rice. And some bread to get all of the remaining sauce off the plate! 🤤

Image under CC-SA license, adapted from Wikipedia.

* What do you mean, there’s fungus in this delicious blue cheese?? 😱

Always-Valid C++ Types

Types don’t always contain what their name implies

Many C++ user-defined types may at time carry information that does not correspond to what their names say. E.g.: a Name object may be empty, which is not a valid name. All code that manipulates these types must handle such invalid cases, or trust that they have been verified elsewhere, which is a common source of bugs.

As an example, let’s consider a type that should contain a MIME string, e.g.: “audio/mp3”. A naive implementation may start like this:

class MIME {
public:
    MIME(const string& mime) : _mime(mime) {}
    bool is_valid() const { /* proper tests */ }
private:
    std::string _mime;
};

Notice that there is no validity checks in the constructor, so any code that manipulates MIME objects will need to call is_valid() before trusting that these objects contain valid MIME data. But sometimes in the spirit of optimization it is tempting to write:

// Only call with a valid mime string!
bool is_audio(const MIME& mime) {
    // This should catch any bad calls, right?
    assert(mime.is_valid());
    ...
}

And this may well pass all your testing, because you have already tested MIME::is_valid() elsewhere so you will think you don’t need to check for invalid MIME strings in is_audio() again… Until you start getting crash reports from the field, when your users handle data of doubtful origin.

Ensure types are valid by construction

One solution would be to add validity checks in the constructor, and throw an exception when a bad string is provided. However this seems quite a strong action to take, as strings that are not MIME types are quite common in the real world, and it would force the user to handle the MIME validation before trying to create a MIME object. Also some projects prefer not to use exceptions at all (like Firefox).

My preferred solution is to hide the too-trusting constructor, and to instead provide a factory function that will verify the given string and will only create a MIME object when that string is valid. Any object generated from this function can now be trusted to always contain valid data.

class MIME {
public:
    static std::optional create(const std::string& mime) {
        if (`mime` is a valid MIME string) {
            return { MIME(mime); }
        }
        return {};
    }
private:
    MIME(const string& mime) : _mime(mime) {}
    std::string _mime;
};

C++17’s optional is of great help here as it forces the caller to do the right thing: The return value must obviously be checked for a valid MIME object, and that object may only be accessed when actually present. Afterwards, that MIME object may be copied, or just passed to other functions as a direct reference; and by contract there is no need for further validity tests.

If you cannot use C++17 yet (and don’t have access to a similar helper type), you could instead return a unique_ptr, at the extra cost of a heap allocation — which may make sense anyway for heavy objects.