• 0 Posts
  • 43 Comments
Joined 1 year ago
cake
Cake day: June 2nd, 2023

help-circle
  • I know looking at it from the outside can look like throwing a fit, but as a software dev I can assure you our professional life is a constellation of papercuts and stumbling blocks on the best days. It is a fun job in many ways but it’s by its nature extremely frustrating at times. For professionals, the inherent frustrations are just the tip of the proverbial iceberg, the rest of the iceberg being induced frustrations due to work environment causes of various nature, and a lot of devs who also develop stuff in their own free time do it to regain a sense of purpose and control.

    If these kinda hiccups keep happening even outside the day job of a developer, it is absolutely understandable that the reaction is simply to cut the bullshit rather than grabbing yet another shovel to shovel away the shit you’ve been covered with this time.

    Ultimately, the cost benefit analysis for keeping uBOL hosted on mozilla’s platform became skewed on the cost side and the additional expense is not one that gorhill can or wants to afford.

    So, yeah, it’s not a hissy fit.




  • Thank you for the explanation, now I understand the context on the original message. It’s definitely an entirely different environment, especially the kind of software that runs on a bunch of servers.

    I have built business programs before being a game dev, still the kinds that runs on device rather than on a server. Even then, I always strived to write the most correct and performant code. Of course, I still wrote bugs like that time that a release broke the app for a subset of users because one of the database migrations didn’t apply to some real-world use case. Unfortunately, that one was due to us not having access to real world databases pr good enough surrogates due to customer policy (we were writing an unification software of sorts, up until this project every customer could give different meanings to each database column as they were just freeform text fields. Some customers even changed the schema). The migrations ran perfectly on each one of the test databases that we did have access to, but even then I did the obvious: roll the release back, add another test database that replicated the failing real world use case, fixed the failing migrations, and re released.

    So yeah, from your post it sounds that either the company is bad at hiring, bad at teaching new hires, or simply has the culture of “lol who cares someone else will fix it”. You should probably talk to management. It probably won’t do anything in the majority of cases, but it’s the only way change can actually happen.

    Try to schedule one on one session with your manager every 2 to 3 weeks to assess which systematic errors in the company are causing issues. 30 minutes sessions, just to make them aware of which parts of the company need fixing.


  • Sorry, this comment is causing me mental whiplash so I am either ignorant, am subject to non-standard circumstances, or both.

    My personal experience is that developers (the decent ones at least) know hardware better than IT people. But maybe we mean different things by “hardware”?

    You see, I work as a game dev so a good chunk of the technical part of my job is thinking about things like memory layout, cache locality, memory access patterns, branch predictor behavior, cache lines, false sharing, and so on and so forth. I know very little about hardware, and yet all of the above are things I need to keep in mind and consider and know to at least some usable extent to do my job.

    While IT are mostly concerned on how to keep the idiots from shooting the company in the foot, by having to roll out software that allows them to diagnose, reset, install or uninstall things on, etc, to entire fleets of computers at once. It also just so happens that this software is often buggy and uses 99% of your cpu taking it for spin loops (they had to roll that back of course) or the antivirus rules don’t apply on your system for whatever reason causing the antivirus to scan all the object files generated by the compiler even if they are generated in a whitelisted directory, causing a rebuild to take an hour rather than 10 minutes.

    They are also the ones that force me to change my (already unique and internal) password every few months for “security”.

    So yeah, when you say that developers often have no idea how the hardware works, the chief questions that come to mind are

    1. What kinda dev doesn’t know how hardware works to at least an usable extent?
    2. What kinda hardware are we talking about?
    3. What kinda hardware would an IT person need to know about? Network gear?

  • ugo@feddit.ittoLinux@lemmy.mlGoldilocks distro?
    link
    fedilink
    arrow-up
    6
    arrow-down
    1
    ·
    21 days ago

    +1. Arch is super easy to install, just open the install guide on the wiki and do what it says.

    It’s also really stable nowadays, I can’t actually remember the last time something broke.

    As a counterpoint, on ubuntu I constantly had weird issues where the system would change something apparently on its own. Like the key repeat resetting every so often (I mean multiple times an hour), weirdness with graphic drivers, and so on.

    That said, I also appreciate debian for server usage. Getting security updates only can be desirable for something that should be little more than an appliance. Doing a dist upgrade scares the shit out of me though, while on arch that’s not even close to a concern.


  • What “it” is configurable? If the code is indented with 4 spaces, it is indented with 4 spaces. You can configure your editor to indent with 1 space if you want, but then your code is not going to respect the 4 spaces of indentation used by the rest of the code.

    I repeat, the only accessible indentation option is using tabs. This is not an opinion because every other option forces extra painful steps for those with vision issues (including, but not limited to, having to reformat the source files to tabs so they can work on them and then reformat them back to using spaces in order to commit them)


  • ugo@feddit.ittoProgramming@programming.devWhy YAML sucks?
    link
    fedilink
    arrow-up
    10
    arrow-down
    2
    ·
    25 days ago

    Hard tabs are the only accessible option though. If you care about developers with a different vision capability than yours, the only correct indentation choice is tabs.

    If, because of bad vision, someone needs to crank the font size way up, it’s very possible that they might need to work with a tabstop of 3, 2, or even just 1 space.

    With tabs, this is user configurable. With spaces it isn’t.



  • We use null objects at work, and as another person said they are a safety feature. Here’s how they work: they are wrappers around another type. They provide the same interface as the wrapped type. They store one global instance of the wrapped type, default initialized, in a memory page marked read-only.

    Here’s why they are considered a safety feature (note: most of this is specific to c++).

    Suppose you have a collection, and you want to write a function that finds an item in the collection. Find can fail, of course. What do you return in that case? Reasonable options would be a null pointer, or std::nullopt. Having find return a std::optional would be perfect, because that’s the exact use case for it. You either found the item or you did not.

    Now, the problem is that in most cases you don’t want to copy the item that was found in the collection when you return it, so you want to return a pointer or a reference. Well, std::optional<T&> is illegal. After all, an optional reference has the same semantics as a pointer, no? This means your find function cannot return an optional, it has to return a pointer with the special sentinel value of nullptr meaning “not found”.

    But returning nullptr is dangerous, because if you forget to check the return value and you accidentally dereference it you invoke undefined behavior which in this case will usually crash the program.

    Here’s where the null object comes in. You make find just return a reference. If the item is not found, you return a reference to the null object of the relevant type. Because the null object always exists, it’s not UB to access it. And because it is default initialized, trying to get a value from it will just give you the default value for that data member.

    Basically it’s a pattern to avoid crashing if tou forget to check for nullptr


  • Meh. Been developing professionally with C++ for 10 years at this point. I’m one of the weird people that kinda likes C++ and its pragmatism despite all its warts.

    I’d like C++ better if it didn’t have inheritance. There are better solutions to model interfaces, and without inheritance people can’t write class hierarchies that are 10 levels deep with a different set of virtual functions overridden (and new virtual functions added) at each level.

    And yes, that is not hypothetical. Real codebases in the real world shipping working products do that, and it’s about as nice as you can imagine.


  • You do have a terminology mismatch. In C++, an abstract class is a class with at least one pure virtual method.

    Such classes cannot be instantiated, so they are useful only as base classes.

    An interface is more of a concept than a thing.

    Sure you can say that Iterable is an interface that provides the Next() and Prev() methods and you can say that Array is an Iterable because it inherits from Iterable (and then you override those methods to do the correct thing), and that’s one way to implement an interface in C++.

    But you can also say that Iterable<T> is a class template that provides a Next() and Prev() methods that call the methods of the same name on the type that they wrap (CRTP aka static polymorphism).

    Or you can say that an algorithm that scans a collection T forward requires the collection to have a Next() method by calling Next() on it.

    And I can think of at least 2 other ways to define an interface that isn’t using abstract classes.

    And even if using abstract classes, inheriting from them is definitely the least flexible way to use them to define an interface, because it doesn’t allow one to do something like mocking functionality in tests, because it’s not possible to redefine the class to be tested to inherit from the test interface implementation with mocked functionality, so one still needs something to the effect of dependency injection anyway.

    So yeah, abstract class is very different from inheritance, and it’s also very different from interface, even though it relates to both.


  • Looks to me like the ruling is saying that the output of a model trained on copyrighted data is not copyrighted in itself.

    By that logic, if I train a model on marvel movies and get something that is exactly the same as an existing movie, that output is not copyrighted.

    It’s a stretch, for sure, and the judge did say that he didn’t consider the output to be similar enough to the source copyrighted material, but it’s unclear what “close enough” is.

    What if my model is trained on star wars and outputs a story that is novel, with different characters with different voices. That’s not copyrighted then, despite the model being trained exclusively on copyrighted data?



  • I think it’s possible that the filesystem ran out of inodes, so even though there is space on disk, there is no space in the filesystem metadata to store new files.

    Now, I don’t know off the top of my head how to check this, but I assume the answer is on the internet somewhere (am on phone and can’t help much more than this, sorry)




  • Reread the OP. They say:

    not on GNOME, because you have a panel at the top

    And

    when usign GTK apps on those [non-GNOME] desktops

    So you would not “access the controls above the app”, because having controls above the app is not covered by this scenario.

    The scenario is:

    1. You don’t have a top panel
    2. You have a maximized GTK app

    Which makes the close button be in the corner of the screen, but without actually extending to it.

    On topic: never knew this was a problem, guess I got spoiled by the Qt environment



  • ugo@feddit.ittoProgrammer Humor@lemmy.mlgot him
    link
    fedilink
    arrow-up
    6
    arrow-down
    1
    ·
    edit-2
    5 months ago

    Since my previous example didn’t really have return value, I am changing it slightly. So if I’m reading your suggestion of “rewriting that in 3 lines and a single nested scope followed by a single return”, I think you mean it like this?

    int retval = 0;
    
    // precondition checks:
    if (!p1) retval = -ERROR1;
    if (p2) retval = -ERROR2;
    if (!p3 && p4) retval = -ERROR3;
    
    // business logic:
    if (p1 && !p2 && (p3 || !p4))
    {
        retval = 42;
    }
    
    // or perhaps would you prefer the business logic check be like this?
    if (retval != -ERROR1 && retval != -ERROR2 && retval != -ERROR3)
    {
        retval = 42;
    }
    
    // or perhaps you'd split the business logic predicate like this? (Assuming the predicates only have a value of 0 or 1)
    int ok = p1;
    ok &= !p2;
    ok &= p3 || !p4;
    if (ok)
    {
        retval = 42;
    }
    
    return retval;
    

    as opposed to this?

    // precondition checks:
    if(!p1) return -ERROR1;
    if(p2) return -ERROR2;
    if(!p3 && p4) return -ERROR3;
    
    // business logic:
    return 42;
    

    Using a retval has the exact problem that you want to avoid: at the point where we do return retval, we have no idea how retval was manipulated, or if it was set multiple times by different branches. It’s mutable state inside the function, so any line from when the variable is defined to when return retval is hit must now be examined to know why retval has the value that it has.

    Not to mention that the business logic then needs to be guarded with some predicate, because we can’t early return. And if you need to add another precondition check, you need to add another (but inverted) predicate to the business logic check.

    You also mentioned resource leaks, and I find that a more compelling argument for having only a single return. Readability and understandability (both of which directly correlate to maintainability) are undeniably better with early returns. But if you hit an early return after you have allocated resources, you have a resource leak.

    Still, there are better solutions to the resource leak problem than to clobber your functions into an unreadable mess. Here’s a couple options I can think of.

    1. Don’t: allow early returns only before allocating resources via a code standard. Allows many of the benfits of early returns, but could be confusing due to using both early returns and a retval in the business logic
    2. If your language supports it, use RAII
    3. If your language supports it, use defer
    4. You can always write a cleanup function

    Example of option 1

    // precondition checks
    if(!p1) return -ERROR1;
    if(p2) return -ERROR2;
    if(!p3 && p4) return -ERROR3;
    
    void* pResource = allocResource();
    int retval = 0;
    
    // ...
    // some business logic, no return allowed
    // ...
    
    freeResource(pResource);
    return retval; // no leaks
    

    Example of option 2

    // same precondition checks with early returns, won't repeat them for brevity
    
    auto Resource = allocResource();
    
    // ...
    // some business logic, return allowed, the destructor of Resource will be called when it goes out of scope, freeing the resources. No leaks
    // ...
    
    return 42;
    

    Example of option 3

    // precondition checks
    
    void* pResource = allocResource();
    defer freeResource(pResource);
    
    // ...
    // some business logic, return allowed, deferred statements will be executed before return. No leaks
    // ...
    
    return 42;
    

    Example of option 4

    int freeAndReturn(void* pResource, const int retval)
    {
        freeResource(pResource);
        return retval;
    }
    
    int doWork()
    {
        // precondition checks
    
        void* pResource = allocResource();
    
        // ...
        // some business logic, return allowed only in the same form as the following line
        // ...
    
        return freeAndReturn(pResource, 42);
    }