-
7 votes
-
Five emerging Australian authors talk about writing their breakthrough novels
7 votes -
Hindu monastic order is reclaiming transgender people’s status in Indian society
9 votes -
MLS Week 1: All Match Discussions
A list of matches for the week: Toronto FC @ Philadelphia Union New York City FC @ Orlando City FC New York Red Bulls @ Columbus Crew New England Revolution @ FC Dallas Real Salt Lake @ Houston...
A list of matches for the week:
Toronto FC @ Philadelphia Union
New York City FC @ Orlando City FC
New York Red Bulls @ Columbus Crew
New England Revolution @ FC Dallas
Real Salt Lake @ Houston Dynamo
Portland Timbers @ Colorado Rapids
Minnesota United FC @ Vancouver Whitecaps
Chicago Fire @ LA Galaxy
FC Cincinnati @ Seattle Sounders
Montreal Impact @ San Jose Earthquakes
Atlanta United FC @ DC United
Sporting Kansas City @ Los Angeles FC9 votes -
Lorn - Sega Sunset (2013)
9 votes -
Climate change: Angela Merkel welcomes school strikes
11 votes -
The Steven Spielberg vs. Netflix battle could mean collateral damage for indies at the Oscars
11 votes -
Revealed: Facebook’s global lobbying against data privacy laws
19 votes -
Bernie Sanders gets personal - the 2020 US hopeful is opening up about his upbringing, recognizing that his singular focus on issues wasn't enough last time
15 votes -
Why Doctors Without Borders is suspending work in the Ebola epicenter in Congo
9 votes -
You Don’t Need All That Complex/Expensive/Distracting Infrastructure
14 votes -
Millennial masterstroke: All credit to Afterpay in generation grab
5 votes -
Why the Galaxy Fold will be a huge success even at $2,000 -- "[...] Samsung has effectively turned into the new Apple. They are the innovators. They are ahead of the game."
22 votes -
The marriage of SpaceX and NASA hasn’t been easy—but it’s been fruitful
10 votes -
Former officer Mohamed Noor pleads not guilty to Justine Ruszczyk Damond’s death
3 votes -
Sydney's 41st Mardi Gras parade celebrates the fearless and the fabulous
5 votes -
Rich Felker, the creator of musl libc, asks the community for financial support via Patreon
9 votes -
I want an emulation box for my TV. What options best fit my needs?
Note: I wasn't sure whether to post this in ~games or ~tech, so if it needs to be moved, feel free to put it where it belongs! I've been playing my Playstation Classic a lot, and it's made me want...
Note: I wasn't sure whether to post this in ~games or ~tech, so if it needs to be moved, feel free to put it where it belongs!
I've been playing my Playstation Classic a lot, and it's made me want to setup a full emulation box for my TV. I started looking into options and quickly got in over my head, so I'm hoping you fine folks can help me sort this out.
Caveat: I am somewhat techy, but not nearly to the same level as the average Tildes user.
Here is a rundown for what I'm going for:
-
Systems: I want to be able to emulate up through the Dreamcast with no slowdown (or, at least, no slowdown as a result of my hardware--if it's natural to the original console or a limitation of the emulator, that's fine).
-
Input: I want to use a wireless controller for input. Ideally six face buttons and four shoulders, so that it can easily stand in for almost all common controller layouts.
-
Graphics: If possible, I'd like to be able to enhance the eye candy a bit with things like upscaling, increasing the internal resolution, and shaders. This would be nice to have, but is not a necessity. Running at fullspeed in the original with no enhancements is the target minimum, though.
-
Footprint: Something up to the size of, well, a retro game console. I don't want a full PC next to my TV, but it doesn't have to be the size of a credit card either.
-
Budget: Let's go with under $400 USD? Given the cost of a Raspberry Pi that seems like overkill, but I know the Pi can't do all the way up to N64/Dreamcast, and I'm not sure how much more power those need. That price limit is flexible if I'm being unreasonable with my expectations.
With all that in mind, here are my questions:
-
What hardware best suits my needs? I am not interested in building my own and am seeking pre-built solutions.
-
What controller is best? I'd prefer to have a one-size-fits-all solution, rather than swapping them out. Six face buttons would help make the Genesis, Saturn, and N64 feel more natural, but I suspect that might be hard to come by?
-
It looks like Retroarch is definitely the way to go for easy setup, but there seem to be a lot of different standalone options (e.g. Lakka, RetroPie, Recalbox). Which one should I go with? I should add that I really only care about ease of use and simplicity. I do not need something flashy, and the less friction in both setup and use, the better.
-
Any other tips, pieces of advice, or resources? I don't have a lot of experience with emulation, so a lot of this is uncharted territory for me, hence my uncertainty and need for guidance.
11 votes -
-
Magic the Gathering announces "Modern Horizons", the first set designed to skip Standard legality and go straight to Modern
13 votes -
Canada has formally commenced the process to extradite Meng Wanzhou, CFO of Huawei to the USA
9 votes -
Amazon to launch new grocery-store business, distinct from Whole Foods
12 votes -
Lyft files first for IPO in litmus test for the industry
16 votes -
Code Quality Tip: Cyclomatic complexity in depth.
Preface Recently I briefly touched on the subject of cyclomatic complexity. This is an important concept for any programmer to understand and think about as they write their code. In order to...
Preface
Recently I briefly touched on the subject of cyclomatic complexity. This is an important concept for any programmer to understand and think about as they write their code. In order to provide a more solid understanding of the subject, however, I feel that I need to address the topic more thoroughly with a more practical example.
What is cyclomatic complexity?
The concept of "cyclomatic complexity" is simple: the more conditional branching and looping in your code, the more complex--and therefore the more difficult to maintain--that code is. We can visualize this complexity by drawing a diagram that illustrates the flow of logic in our program. For example, let's take the following toy example of a user login attempt:
<?php $login_data = getLoginCredentialsFromInput(); $login_succeeded = false; $error = ''; if(usernameExists($login_data['username'])) { $user = getUser($login_data['username']); if(!isDeleted($user)) { if(!isBanned($user)) { if(!loginRateLimitReached($user)) { if(passwordMatches($user, $login_data['password'])) { loginUser($user); $login_succeeded = true; } else { $error = getBadPasswordError(); logBadLoginAttempt(); } } else { $error = getLoginRateLimitError($user); } } else { $error = getUserBannedError($user); } } else { $error = getUserDeletedError($user); } } else { $error = getBadUsernameError($login_data['username']); } if($login_succeeded) { sendSuccessResponse(); } else { sendErrorResponse($error); } ?>A diagram for this logic might look something like this:
+-----------------+ | | | Program Start | | | +--------+--------+ | | v +--------+--------+ +-----------------+ | | | | | Username +--->+ Set Error +--+ | Exists? | No | | | | | +-----------------+ | +--------+--------+ | | | Yes | | v | +--------+--------+ +-----------------+ | | | | | | | User Deleted? +--->+ Set Error +->+ | | Yes| | | +--------+--------+ +-----------------+ | | | No | | v | +--------+--------+ +-----------------+ | | | | | | | User Banned? +--->+ Set Error +->+ | | Yes| | | +--------+--------+ +-----------------+ | | | No | | v | +--------+--------+ +-----------------+ | | | | | | | Login Rate +--->+ Set Error +->+ | Limit Reached? | Yes| | | | | +-----------------+ | +--------+--------+ | | | No | | v | +--------+--------+ +-----------------+ | | | | | | |Password Matches?+--->+ Set Error +->+ | | No | | | +--------+--------+ +-----------------+ | | | Yes | | v | +--------+--------+ +----------+ | | | | | | | Login User +--->+ Converge +<--------+ | | | | +-----------------+ +---+------+ | | +-----------------+ | v +--------+--------+ | | | Succeeded? +-------------+ | | No | +--------+--------+ | | | Yes | | v v +--------+--------+ +--------+--------+ | | | | | Send Success | | Send Error | | Message | | Message | | | | | +-----------------+ +-----------------+It's important to note that between nodes in this directed graph, you can find certain enclosed regions being formed. Specifically, each conditional branch that converges back into the main line of execution generates an additional region. The number of these distinct enclosed regions is directly proportional to the level of cyclomatic complexity of the system--that is, more regions means more complicated code.
Clocking out early.
There's an important piece of information I noted when describing the above example:
. . . each conditional branch that converges back into the main line of execution generates an additional region.
The above example is made complex largely due to an attempt to create a single exit point at the end of the program logic, causing these conditional branches to converge and thus generate the additional enclosed regions within our diagram.
But what if we stopped trying to converge back into the main line of execution? What if, instead, we decided to interrupt the program execution as soon as we encountered an error? Our code might look something like this:
<?php $login_data = getLoginCredentialsFromInput(); if(!usernameExists($login_data['username'])) { sendErrorResponse(getBadUsernameError($login_data['username'])); return; } $user = getUser($login_data['username']); if(isDeleted($user)) { sendErrorResponse(getUserDeletedError($user)); return; } if(isBanned($user)) { sendErrorResponse(getUserBannedError($user)); return; } if(loginRateLimitReached($user)) { logBadLoginAttempt($user); sendErrorResponse(getLoginRateLimitError($user)); return; } if(!passwordMatches($user, $login_data['password'])) { logBadLoginAttempt($user); sendErrorResponse(getBadPasswordError()); return; } loginUser($user); sendSuccessResponse(); ?>Before we've even constructed a diagram for this logic, we can already see just how much simpler this logic is. We don't need to traverse a tree of if statements to determine which error message has priority to be sent out, we don't need to attempt to follow indentation levels, and our behavior on success is right at the very end and at the lowest level of indentation, where it's easily and obviously located at a glance.
Now, however, let's verify this reduction in complexity by examining the associated diagram:
+-----------------+ | | | Program Start | | | +--------+--------+ | | v +--------+--------+ +-----------------+ | | | | | Username +--->+ Send Error | | Exists? | No | Message | | | | | +--------+--------+ +-----------------+ | Yes | v +--------+--------+ +-----------------+ | | | | | User Deleted? +--->+ Send Error | | | Yes| Message | +--------+--------+ | | | +-----------------+ No | v +--------+--------+ +-----------------+ | | | | | User Banned? +--->+ Send Error | | | Yes| Message | +--------+--------+ | | | +-----------------+ No | v +--------+--------+ +-----------------+ | | | | | Login Rate +--->+ Send Error | | Limit Reached? | Yes| Message | | | | | +--------+--------+ +-----------------+ | No | v +--------+--------+ +-----------------+ | | | | |Password Matches?+--->+ Send Error | | | No | Message | +--------+--------+ | | | +-----------------+ Yes | v +--------+--------+ | | | Login User | | | +--------+--------+ | | v +--------+--------+ | | | Send Success | | Message | | | +-----------------+Something should immediately stand out here: there are no enclosed regions in this diagram! Furthermore, even our new diagram is much simpler to follow than the old one was.
Reality is rarely simple.
The above is a really forgiving example. It has no loops, and loops are going to create enclosed regions that can't be broken apart so easily; it has no conditional branches that are so tightly coupled with the main path of execution that they can't be broken up; and the scope of functionality and side effects are minimal. Sometimes you can't break those regions up. So what do we do when we inevitably encounter these cases?
High cyclomatic complexity in your program as a whole is inevitable for sufficiently large projects, especially in a production environment, and your efforts to reduce it can only go so far. In fact, I don't recommend trying to remove all or even most instances of cyclomatic complexity at all--instead, you should just be keeping the concept in mind to determine whether or not a function, method, class, module, or other component of your system is accumulating technical debt and therefore in need of refactoring.
At this point, astute readers might ask, "How does refactoring help if the cyclomatic complexity doesn't actually go away?", and this is a valid concern. The answer to that is simple, however: we're hiding complexity behind abstractions.
To test this, let's forget about cyclomatic complexity for a moment and instead focus on simplifying the refactored version of our toy example using abstraction:
<?php function handleLoginAttempt($login_data) { if(!usernameExists($login_data['username'])) { sendErrorResponse(getBadUsernameError($login_data['username'])); return; } $user = getUser($login_data['username']); if(isDeleted($user)) { sendErrorResponse(getUserDeletedError($user)); return; } if(isBanned($user)) { sendErrorResponse(getUserBannedError($user)); return; } if(loginRateLimitReached($user)) { logBadLoginAttempt($user); sendErrorResponse(getLoginRateLimitError($user)); return; } if(!passwordMatches($user, $login_data['password'])) { logBadLoginAttempt($user); sendErrorResponse(getBadPasswordError()); return; } loginUser($user); sendSuccessResponse(); } $login_data = getLoginCredentialsFromInput(); handleLoginAttempt($login_data); ?>The code above is functionally identical to our refactored example from earlier, but has an additional abstraction via a function. Now we can diagram this higher-level abstraction as follows:
+-----------------+ | | | Program Start | | | +--------+--------+ | | v +--------+--------+ | | | Attempt Login | | | +-----------------+This is, of course, a pretty extreme example, but this is how we handle thinking about complex program logic. We abstract it down to the barest basics so that we can visualize, in its simplest form, what the program is supposed to do. We don't actually care about the implementation unless we're digging into that specific part of the system, because otherwise we would be so bogged down by the details that we wouldn't be able to reason about what our program is supposed to do.
Likewise, we can use these abstractions to hide away the cyclomatic complexity underlying different components of our software. This keeps everything clean and clutter-free in our head. And the more we do to keep our smaller components simple and easy to think about, the easier the larger components are to deal with, no matter how much cyclomatic complexity all of those components share as a collective.
Final Thoughts
Cyclomatic complexity isn't a bad thing to have in your code. The concept itself is only intended to be used as one of many tools to assess when your code is accumulating too much technical debt. It's a warning sign that you may need to change something, nothing more. But it's an incredibly useful tool to have available to you and you should get comfortable using it.
As a general rule of thumb, you can usually just take a glance at your code and assess whether or not there's too much cyclomatic complexity in a component by looking for either of the following:
- Too many loops and/or conditional statements nested within each other, i.e. you have a lot of indentation.
- Many loops in the same function/method.
It's not a perfect rule of thumb, but it's useful for at least 90% of your development needs, and there will inevitably be cases where you will prefer to accept some greater cyclomatic complexity because there is some benefit that makes it a better trade-off. Making that judgment is up to you as a developer.
As always, I'm more than willing to listen to feedback and answer any questions!
25 votes -
Socialists win big in Chicago
14 votes -
Memes are our generation's protest art
13 votes -
"Deep Adaptation": A paper that predicts an inevitable near-term social collapse due to climate change
26 votes -
The top six medical inventions during the American civil war
9 votes -
Inside Facebook’s war on hate speech: An exclusive embed with Facebook’s shadow government
14 votes -
Feature suggestion: Bookmark posts from front page
I'd like to be able to bookmark posts from the front page. Right now it really isn't an issue yet since posting frequency is low, but I often quickly check the front page for interesting reads,...
I'd like to be able to bookmark posts from the front page. Right now it really isn't an issue yet since posting frequency is low, but I often quickly check the front page for interesting reads, while not having the time to actually read them. I'd like to see a "Bookmark" button on front page posts that allow me to save those posts for later when I actually do have time to read the posts.
For quick scrolls over the front page, tapping the post and then bookmarking is one click too many.
You could argue I'm lazy, I call it efficiency.While on the subject, if I click "bookmark" on a topic, it'll read "bookmarked" but does not offer an "unbookmark" option until I refresh the page. Since I have big thumbs(large bones) I often tap wrong, so it could be nice if there was a quick way to undo this, similar to how we can undo votes.
Edit: this seems to be a bug: it does work for comments.
Edit2: Made this into an issue.24 votes -
Battles - Ddiamondd (2007)
9 votes -
Feature suggestion: Highlighted text in comment automatically creates quote when you respond to that comment
I'm fairly sure it's either a Reddit or RES feature, but whenever I select text in a comment and then click Reply, it'll copy that text to the comment box and add a > in front so it'll turn into a...
I'm fairly sure it's either a Reddit or RES feature, but whenever I select text in a comment and then click Reply, it'll copy that text to the comment box and add a > in front so it'll turn into a quote. It makes it a little quicker to respond to a specific part of someone's message.
I'm no IT bird and as such I don't know if this is something that can be implemented easily(if at all). It'd also require more JS, not sure if that's an issue as well.
In any case, let me know what you think.
Edit: I'd like to suggest something else, should I make a secondary post or append it to this one? I'd like to avoid cluttering up the front page.
37 votes -
Galaxy S10 Plus review
3 votes -
US President Donald Trump ordered officials to give Jared Kushner a security clearance
11 votes -
Farmers markets lies exposed
6 votes -
What are you reading these days? #14
What are you reading currently? Fiction or non-fiction, any genre, any language! Tell us what you're reading, and talk a bit about it. Notes: I could not start the thread yesterday on Friday like...
What are you reading currently? Fiction or non-fiction, any genre, any language! Tell us what you're reading, and talk a bit about it.
Notes: I could not start the thread yesterday on Friday like I used to, I'm sorry for the delay.
Past weeks: Week #1 · Week #2 · Week #3 · Week #4 · Week #5 · Week #6 · Week #7 · Week #8 · Week #9 · Week #10 · Week #11 · Week #12 · Week #13
16 votes -
Running a bakery on Emacs and PostgreSQL
4 votes -
Soy sauce is one of the most important ingredients in Japanese cooking, but chances are you've never tasted the real thing
24 votes -
Logical Consequence
4 votes -
US fake university racket: Students had no way to check Farmington's authenticity
5 votes -
Not all sleep is equal when it comes to cleaning the brain
16 votes -
I made a 2,000-word analysis of Robert Heinlein’s "All You Zombies" (with visuals!)
12 votes -
UC terminates Elsevier subscription citing unstable fees and irreconcilable differences in approach to open research
12 votes -
Shock rise in global measles outbreaks 'disastrous' for children, UN warns
8 votes -
Pedestrian deaths reach highest level in decades, US report says
8 votes -
Donald Trump and Kim Jong-un summit ends in disarray but there are lessons to be learnt, experts say
11 votes -
A sports hijab has France debating the Muslim veil, again
10 votes -
The latest diet trend is not dieting
6 votes -
Jimmy Eat World - Pol Roger
6 votes -
The yum cha (dim sum) rules you need to know
9 votes -
Amazon announces "Project Zero", a program which will allow brands to directly remove counterfeit listings
11 votes