Threads Are a Bad Idea for Most Purposes (1995) [pdf] - <AUTHOR> https://web.stanford.edu/~ouster/cgi-bin/papers/threads.pdf <comment><USER2> I started doing massively parallel programming on SGI systems around the time this paper was published. SGI's at the time could have 64 CPUs in a single system image, which was very novel. Sun was working on its early multi core workstations, and companies like Cray were pushing different models of distributed computation.

This paper came at a time when threads were really painful to work with. POSIX threads were still new and mostly unsupported, so you were stuck with whatever your OS exposed. On IRIX, you would do threads yourself by forking and setting up a shared memory pool, on Solaris, you had the best early pthread support, in Java, you used the native Thread classes which only really worked on Solaris at the time. It was a mess!

This mess is now solved. Pthreads are everywhere, C++ has std::thread, Java threads work everywhere, and we've had many new language some out which handle parallelism beautifully - for example, the consumer/producer model built into channels in Go is very elegant. The odd one out is Win32, but it's close enough to pthreads for the same concepts to apply.

Event driven programming has also become threaded, this is how the whole reactive family of frameworks, node.js, etc, handle parallelism.

As someone who's been doing this for a long time, what I find confusing is higher level constructs that try to hide the notion of asynchronous operations, such as futures, promises. As a concept, they're fine, but they're difficult to debug because most developer tools seem not to care about making debugging threads easier.

<comment><USER3> > _This mess is now solved._

If you say so. I can't count the dollars I've made fixing other people's poorly written multithreaded code in my entire career, including in the last 3 years.

Thread support is [more or less] standardised in all major OS-es now, sure. Doesn't change the fact that it's an extremely bad fit for the human brain to think about parallelism.

Stuff like actors with a message inbox (Erlang/Elixir's preemptive green threads) or parallel iterators transparently multiplexing work on all CPU cores (Rust's `rayon` comes to mind) are much better abstractions for us the poor humans to think in terms with. Golang's goroutines are... okay. Far from amazing. Still a big improvement over multithreaded code as you pointed out though, I fully agree with that.

I might be projecting here and please accept my sincere apologies if so, but it seems to me you are a bit elitistic in your comment. Multithreaded programming is still one of the most problematic activities even for senior programmers, to this day. Multithreading bugs get written and fixed every day.

At this point I believe we should just move to hardware-enabled preemptive actors where message passing is optimised on the hardware level, and just end all parallelism disputes forever since they are an eternal distraction. (The overhead when utilising message passing today is of course not acceptable in no small amount of projects. Hence the hardware suggestion.)

<comment><USER4> > Doesn't change the fact that it's an extremely bad fit for the human brain > to think about parallelism.

I'm curious why you feel this way? Certainly anything with multiple (more than one) thread is a lot harder than single threaded. Given.

But I think the human experience is rich with real world counterparts that can make multithreaded programming "natural" (not necessarily easy, there's a difference). Basically any process in real life you do that involves collaborating with multiple people is a collaborative multi-threaded process. When forced to grapple with multi-threaded solutions, I often ask myself, "if I had a room full of people working on this problem, what would have to be in place to make the operation flow smoothly?" For me, this anthropomorophisation of the process makes it a "good fit" for how my brain is used to solving lots of real world problems.

On the flip side, I haven't had a lot of luck finding real world experiences that I can model coroutines/async/etc on. So they may be ultimately easier, but if our rubrik for "fit for the human brain to think about" is what the wealth of human experience has evolved our brain to handle well, I'm less convinced.

But I like learning new things. Maybe I just haven't seen the lightbulb yet. Help me see your point of view?

<comment><USER5> The greatest programmers in the world cannot write bug free C level threading code. It is a task beyond human capabilities.

<comment><USER6> I don't follow - are you asserting that, by contrast, the greatest programmers in the world can write bug-free single-threaded code?

<comment><USER7> I think the implication is to stop using C.

<comment><USER3> I'd interpret it to stop using the pthreads model of the parallel coding, in general. Because the pthreads model exists and is used in many programming languages.

But stopping to use C is a good start (for whoever has the choice)!

<comment><USER8> Maybe the functional programming/managed code fans should step up to the plate and rewrite the operating systems, desktop environments, and hundreds of thousands of command line tools etc that have all been implemented in C or C++.

Not as toy, proof-of-concepts. Fully fledged replacements for all that stuff that can be used in our our daily work. Build distros of the stuff so that we don't have to pick and choose this stuff and replace the bits of our systems in a piecemeal fashion.

They could show us how it's done instead of talking endlessly about it in online forums. So let's face it, it's never going to happen.

<comment><USER3> Hm, where did I say anything about FP?

As for managed code, it's being used with huge success in a lot of places (not in OS-es or drivers, yes) but that's quite the huge topic by itself.

<comment><USER8> I never implied you did, they are merely one of the two major major groups of programmers I see consistently deriding C based infrastructure that presumably enables their paychecks to a large extent.

I'm not defending C, I'm merely sneering at its noisy detractors who spend more time complaining about it than supplanting it.

</comment></comment></comment></comment></comment></comment></comment></comment></comment></comment><comment><USER9> I'm not exactly sure if events are easier to debug. I use tornado (event-based Python webserver library) extensively at work - when something goes wrong you don't get a nice stack trace, you get some random sampling of callback spaghetti. Also the _default_ state of matters is that everything is serialized in a single thread and everything waits for their predecessor, even when they are totally unrelated, though that probably tells more about the particular framework than event-based programming in general.

I'd rather use a real multithread-based framework, honestly, though I concede that it also opens up different ways of making developers' lives miserable.

<comment><USER10> It's time to migrate to async/await. Check out asyncio.Protocols for TCP servers and aiohttp for HTTP servers. We get beautiful async stack traces delivered to Sentry. Debugging anything is a joy.

<comment><USER11> I'm always a +1 for aiohttp (and aiopg)'s ease of use

</comment></comment></comment><comment><USER12> The author, in case anyone didn't recognize the name:

[https://en.wikipedia.org/wiki/John_Ousterhout](https://en.wikipedia.org/wiki/John_Ousterhout)

Specifically, he created the Tcl programming language, which had a nice event loop way back when.

<comment><USER13> It's still there! IIRC you could also have arbitrarily many nested event loops, for better or worse. And some threading support is also available [1], although it seems to be culturally disapproved of.

1\. [https://wiki.tcl-lang.org/page/thread](https://wiki.tcl- lang.org/page/thread)

<comment><USER12> I just meant to say that it was already in place... uh...holy crap... 25 years ago.

<comment><USER14> Technically it was part of Tk. It got grafted into mainline Tcl 20 years ago.

</comment></comment></comment></comment><comment><USER15> A shame that no one has mentioned cache invalidation as further reason threaded programming is hard. One my biggest takeaways from Martin Thompson's talk on mechanical sympathy is that the first thing he tries when brought in as a performance consultant is to turn off threading. He mentions locking as a performance problem but that these days cache locality can be the key to speeding up slow applications.

<comment><USER16> Yeah, it was hard to realize in 1995, but nowadays pretty much everyone who tried experienced performance problems with threads, or rather with shared memory multithreading concurrency model. It doesn't actually scale if you idiomatically synchronize shared memory access with locks or atomics, you need some way to batch things and amortize the cost of synchronization between cores while also preserving locality, which ultimately implies an asynchronous model where threads are just a low level implementation detail.

<comment><USER15> I've been hearing rumors that AMD's current offerings have been starting to avoid even shared cache between processors. It boggles my mind that any CPU designer would think a shared L2 cache is a good idea. Makes me wonder where my model of memory starts to break down. I always just think of L2 as being slower, less expensive memory than L1. I'm wondering if there are any benefits that actually outweigh the cache eviction penalty of multiple processors accessing it...

<comment><USER17> It's surely an engineering tradeoff resulting from weighing the different pros/cons. If you had dedicated cache per core at 1/Nth the size, much of it would be wasted when you're running less than full tilt -- eg, if you're using 2/4 cores then half of the cache is artificially unavailable instead of doubling the cache available to those 2 cores.

</comment></comment></comment></comment><comment><USER18> A thread from 2017: [https://news.ycombinator.com/item?id=14547063](https://news.ycombinator.com/item?id=14547063)

Way back in 2008: [https://news.ycombinator.com/item?id=399670](https://news.ycombinator.com/item?id=399670)

<comment><USER19> > A thread from 2017

Didn't you read the article?!

<comment><USER20> Did you click on the links in the comment above yours? ;-)

<comment><USER21> Whoosh

<comment><USER22> The perniciousness of winky face is on full display here

</comment></comment></comment></comment></comment><comment><USER23> You have two choices when it comes to utilizing multiple cores: threads and processes. Threads are hard, but sharing data between processes is hardly any easier.

Maybe they're a bad idea, but these days you have no choice but to learn how to use threads. AMD's run-of-the-mill processors have 16 cores, Intel's 8. Servers have lots more. Heck even your iPhone has 6.

The clock rate on CPUs isn't getting any better. It's just more cores from here on.

<comment><USER24> It being hard to share memory is a feature, not a bug.

Threads make any single thing on your program mutable without your direct control. Processes keep the mutability scoped into a few hard to extend areas.

<comment><USER25> > Threads make any single thing on your program mutable without your direct > control.

No they don't. Threads don't mutate random variables by themselves, you need actual code that does the mutation (whether it's running on a separate thread or not).

I mean, how is that statement different from "calling other functions makes any single thing on your program mutable"?

<comment><USER24> > how is that statement different from "calling other functions makes any > single thing on your program mutable"?

On those languages where functions mutate things, that's basically true. But it's much more common that functions can only mutate global variables, and people keep those in low numbers, exactly for that reason. Actually, replace "functions" with "methods" and you will get into one of the largest flaws of OOP.

But anyway, mutability is much less of a problem outside of concurrent code.

</comment></comment></comment></comment><comment> awinter-py > Threads should be used only when true CPU concurrency is needed

> Scalable performance on multiple CPUs

the exceptions to 'when to use threads' in 1995 sound like SOP these days

</comment><comment><USER26> Threads have some very practical advantages:

* Standard, easy way to get a backtrace

* Standard, easy way to get a list of active things going on

* In many cases, threads make it easy to follow control flow

<comment><USER27> Yet threads make backtraces and control flow much less useful, since they miss out important context from concurrent threads.

I wouldn't personally say that threads make control flow easier to follow: we might gain a little by disentangling separate activities into threads, but we lose _a lot_ when these get interleaved in arbitrary, non-deterministic ways.

<comment><USER28> > Yet threads make backtraces and control flow much less useful, since they > miss out important context from concurrent threads.

I mean, when a program panics, you get a stacktrace from (a consistent snapshot of) _all_ the threads, so what's the problem?

<comment><USER29> If a highly concurrent service gets a query'o'death, it's hard to tell which threads were working on it and which were merely within the blast radius. Frameworks tend to roll their own notion of "request context" without it being strongly typed or pervasive across the language and libraries.

<comment><USER28> Now I'm curious what backtraces from Postgres look like when parallel scans are enabled. IIRC, you've got one isolated fork(2)ed master for the connection, which then has threads to divide work. Not _too_ bad to debug.

</comment></comment></comment></comment></comment><comment><USER30> It's not that threads are necessarily a bad idea (though they can be for performance reasons), but that programming with most synchronization primitives is a bad idea. If you program with message passing, then it's not much different from the "events" model except that in the event-driven model you're trying to hide the underlying abstraction more (you still have concurrency, it's just baked into the I/O library).

I honestly think this presentation is confused. "Concurrency is fundamentally hard; avoid whenever possible" seems to go against their own argument. Event- driven models (which rely on message passing) are still doing concurrency, except instead of using locks and semaphores to synchronize things, you're using mailboxes and channels.

Even CPU interrupts are a form of concurrency that is similar to event-driven models. Just because you're not spawning a thread and acquiring a lock, doesn't mean you're not doing concurrency.

<comment><USER31> Event driven concurrency is not really easier than threads with primitive blocking synchronisation. Races are still possible, instead of deadlocks you can have livelocks, resource control and backpressure are non-trivial etc.

<comment><USER30> That's true, but at least you can handle backpressure at the runtime level and just choose a predetermined strategy for dealing with it (i.e. start dropping messages, exponential backoff, etc)

</comment></comment></comment><comment><USER32> IMHO I think one large part of it is synchronization. If you're having to synchronize things all the time, you're probably misusing threads and should be using a different execution model.

<comment><USER33> Another way to look at it is that only infrastructure should be locking stuff, and infrastructure should be a very tiny part of the codebase. That infrastructure should probably be responsible for layering a different concurrency paradigm on top of threads...

Most platforms these days provide such things as part of the language, or in the standard library, or as a freely-available package. Writing one's own concurrency infrastructure is usually unnecessary, but when it is needed, it needs to be kept as small and as easily-auditable as possible.

A bit like `unsafe` in Rust, in fact.

Locking all over the place generally indicates that someone's trying to shotgun-debug concurrency bugs. I've had to use libraries which did that, and wished horrible things upon those responsible.

</comment></comment><comment><USER34> > Threads should be used only when true CPU concurrency is needed.

Which is basically any program running on any modern processor.

<comment><USER35> Not at all. There are multiple cores, sure, but why does my program have to use them? If it performs adequately using only one core, and if the nature of the problem doesn't require threads, why should I make it multithreaded just because the processor has multiple cores?

</comment></comment><comment><USER36> Raw threads are really hard to program correctly, however sinking parallel code into an executor or queuing framework tends to really reduce complexity and in a lot of cases get all the cores working.

</comment><comment><USER37> In my life I must have written at least a few million lines of code. Probably more. How many of those lines have been explicitly multithreaded? A few thousand lines, at most.

</comment><comment><USER38> I think this was truly the most amazing thing about learning Rust. After having experienced the pain (the issues brought up in the linked slide deck) of threads in C, then C++ and Java, it was wild to work with a language that provided some significant safety rails for working with data across threads.

Now async/await gives us even better options on top of that, but it's truly what made me enjoy the language so much. This article is what resonated with me and got me to invest so much spare time over the last 5 years in working with Rust: [https://blog.rust-lang.org/2015/04/10/Fearless- Concurrency.h...](https://blog.rust-lang.org/2015/04/10/Fearless- Concurrency.html)

<comment><USER39> Rust does a great job here, but so do languages that make multithreading safer at a higher level -- Erlang/OTP and Haskell are two great examples. Immutable data may not solve every concurrency problem, but it sure goes a long way.

I also have a lot of respect for Ada's task-based concurrency approach (independent actors, communicating by rendezvous). You don't get the flexibility to roll your own concurrency strategy in Ada, but the language's support for its chosen mechanism is truly excellent. Even if you'll never use Ada, this part of the language is worth studying just as an example of great engineering design.

<comment><USER40> There's a nice Kevlin Henney talk where he lays out this diagram:

                                     |
           non-shared mutable state  |  shared mutable state
                                     |
         </comment></comment></comment><comment></comment><comment></comment><comment></comment><comment>----+</comment><comment></comment><comment></comment><comment></comment><comment>
                                     |
          non-shared immutable state | shared immutable state
                                     |

Each quadrant is safe, except the one in the top right: shared mutable state.

Functional languages are great at the bottom two, since they strongly encourage immutable state. Message-passing based concurrency strongly encourages non-shared state, the safe two on the left.

Rust is the only language I've seen which encourages all three safe quadrants, while making the fourth a compile-time error.

<comment><USER41> > Each quadrant is safe, except the one in the top right: shared mutable > state.

No. Your database is one giant shared mutable state.

How is using a database safe then? Transactions.

Haskell has had software transactional memory for fifteen years now. Microsoft tried to copy it in .NET but it's nearly impossible to do right in a language without clear separation of pure and impure code.

<comment><USER42> " _> Each quadrant is safe, except the one in the top right: shared mutable state.

No. Your database is one giant shared mutable state.

How is using a database safe then? Transactions._"

Transactions are less an occasion where shared mutable state is made 'safe' during concurrency and more a situation where concurrent processes are forced to temporarily interact and operate in a sequential, non-concurrent, manner. They use locks under the covers. Databases manage to be parallel because different processes operate on different sets of data at the same time; they lock when two or more processes attempt to access the same row on a table. Transactional state access is still vulnerable to deadlocks and other difficulties of concurrent programming. This means that transactional state is not 'safe' in the same way that immutable and non-shared state are safe. It's just a much easier way of managing the kind of difficulties you have with shared mutable state than say, raw locks.

<comment><USER41> No. Please read about MVCC: [https://en.m.wikipedia.org/wiki/Multiversion_concurrency_con...](https://en.m.wikipedia.org/wiki/Multiversion_concurrency_control)

The tl;dr is that

> Locks are known to create contention especially between long read > transactions and update transactions. MVCC aims at solving the problem by > keeping multiple copies of each data item. In this way, each user connected > to the database sees a snapshot of the database at a particular instant in > time. Any changes made by a writer will not be seen by other users of the > database until the changes have been completed (or, in database terms: until > the transaction has been committed.)

In other words, the system uses immutable state under the hood plus some atomics/locking to present the abstraction of safe shared mutable state.

</comment></comment></comment></comment><comment><USER43> Part of me thinks the success of javascript is due precisely for the reason that it prevents/discourages multithreaded programming.

</comment><comment><USER44> I've found C# to be one of the easier languages to do multithreading with. I think this is owing to the capabilities of a Visual Studio like parallel stack viewer.

Also, anyone working with an OOP should really read Java Concurrency in Practice. That really helps in terms of learning how to think about multiple threads in a OOP world.

Not sure how events by themselves can solve the threading issues as events can be multi-threaded too. I've seen people write far worse event driven code than multi-threaded code. If people want to use events heavily, I think it's better to use a well known design pattern so others can understand what you are trying to do.

</comment><comment><USER45> I haven't directly interacted with threads in a very long time, but I do use Microsoft's Task Parallel Library on a daily basis. I feel like once you understand TPL/async/await and the nuances with execution context and how to handle CPU vs IO bound operations, things come together really nicely. I do not really worry about things like cache coherency or the low-level synchronization primitives involved anymore. I can seamlessly throw in some locking with my TPL usage (typically ReaderWriterLockSlim) without much concern for strange behavior across the various tasks. It really does "just work" once you buy-in 100% (i.e. exclusively use TPL abstractions throughout).

I would say that 99% of the time I am dealing with IO (simply awaiting some asynchronous database/network operation), with the other 1% of cases being things that I actually want to explicitly spread across multiple parallel execution units - I.e. Task.Run() or Parallel.ForEach(). In either case, I am working with the sugar-coated TPL experience, and all the horrific threading code is handled automagically. If I still had to work with threads directly, I would probably have found a different career path by this point.

<comment><USER46> What problems of threads is this actually isolating you from? It seems like the usual problems of correctly protected shared mutable state and avoiding deadlock are still there if you're using low-level primitives like ReaderWriterLockSlim.

<comment><USER45> I simply cite RWLS as an example of how you can combine other primitives into the threading model afforded by TPL without much frustration. I make no claims that it somehow eliminates fundamental concerns like shared state. In practice, I use RWLS extremely rarely because I prefer to avoid shared mutable state in the first place. I will spend an entire weekend reworking architecture in order to get a lock out of a hot path if I need to. 99% of my task-related code is boring stuff like:

      var session = await _connection.QueryFirstAsync<Session>(GetSessionSql, some session token);

The biggest concern for me is simply the thread lifecycle and # of threads involved. TPL handles a thread pool for you and automatically schedules Tasks to run on these threads as appropriate. This is a non-trivial affair which would be painful to re-implement consistently and reliably in each application. I, for one, would be far too tempted to waste entire days screwing with thread pool parameters relative to environmental factors. With TPL hiding these things from me, I can focus on a level of abstraction that actually gets business features shipped. I still have not run into a scenario where I would have rather gotten my hands dirty and implemented the raw threads myself. Microsoft did a pretty damn good job. Everything "just works" and it scales very well.

</comment></comment></comment><comment><USER47> In C++ it has become way easier to manage some of the issues mentioned since 1995, namely by using atomic, future or even locks.

</comment><comment><USER48> Events are not only an alternative to threads they are also a complement. If your language environment has a complex memory model with good concurrency support and stable non-blocking IO, you can use threads! But for them to be good you need to make sure that the input and output is compatible, as a general guide:

1) Make sure your hardware interface is capable of being accessed by the kernel from multiple threads. Network cards generally allow this, while graphics cards still don't, at least without a lot of overhead.

2) Make sure your application profits form parallelism, and specifically joint parallelism; which is my term for computing that allows many threads to work on the same memory.

Bottom line is in my case only the Java server for my MMO will use threads in a "joint parallel" way. In everything else I will avoid them like a jerrycan full of gas tries to avoid fire.

So I'm transitioning to C with arrays!

</comment><comment><USER49> Years ago, an OpenBSD developer told me, "threads are for idiots" in response to a bug I had submitted. At the time, I was a bit offended (it was a good, reproducible bug report), but today, I think he was right. They're just too complicated and 90% of the time they are not needed.

<comment><USER50> > Years ago, an OpenBSD developer told me, "threads are for idiots" in > response to a bug I had submitted. At the time, I was a bit offended (it was > a good, reproducible bug report), but today, I think he was right.

Whether he was right or not about threads, it's offensive to insult the person just because you don't like their idea. Likewise for this to be the response to a bug report - if you don't want to support threads, then don't support them rather than lashing out at people who notice your support is buggy.

I think in 2020 he's mostly wrong anyway. Sure, there have been many problems with threads, but...

* this presentation's "Threads should be used only when true CPU concurrency is needed" maybe meant "rarely" in "1995" but means "commonly" in 2020 when single-core performance has been mostly stalled for a while and core counts have risen dramatically.

* There are safer/easier alternate concurrency primitives than mutexes (channels) and at least partial solutions to major problems with threading. For example, in safe Rust there are no data races (even when synchronizing via mutexes). Other problems (deadlocks, contention, other types of race conditions) still exist of course.

* "Threads" vs "events (event loops + callbacks)" as described in this 1995 presentation isn't the whole world, especially today. What about communicating sequential processes with no shared mutable state (such as Erlang's actors)? So to some extent I disagree with the framing of the problem altogether.

* callbacks have their own problems beyond what's described in this presentation. Some that were widespread even in 1995: a string of operations written as a string of callbacks is a lot harder to understand than ones written with the "sequential composition operator" (;) and loops. (Callbacks are basically abandoning structured programming in favor of goto at the macro level.) Likewise harder to debug: you can't just get a stack trace and understand its current state. And some that have become more common since then. These days, event loops are usually multithreaded, so for any cross-request state you have the threading problems as well as the event loop problems. Today I'd say callbacks are the advanced, use them if you need the performance but be wary of the dangers option.

</comment></comment><comment><USER51> libuv ([http://docs.libuv.org/en/v1.x/design.html](http://docs.libuv.org/en/v1.x/design.html)) is pretty much this in action. Event loops are not necessarily easy to debug though and message passing between event loops will force the use of concurrency primitives such as mutexes and/or memory barriers (lock-free) anyway. Also, working with event-driven architecture requires a more functional approach since the handlers are all short-lived. Reminds me of Erlang. I think the deck downplays the complexity of building such a system.

<comment><USER12> The author of the deck is Dr. John Ousterhout, who wrote Tcl, which had an event loop way back in the day.

</comment></comment><comment><USER52> Sure, only use threads when you actually need them. The cases where you actually need them are quite numerous, though. E.g., you have a library that connects to something over the network but the library is blocking. Or you need to respond to events quickly but for some events you need expensive calculations. If you can get away with copying data to the threads so shared state is minimized this will help. The general principle is to make things as easy as possible instead of as difficult as possible.

</comment><comment><USER53> It is amazing, and sad, how many people still refer to this document today when complaining about how "threads are bad" and "events are the bee's knees" or when justifying some architectural decision to avoid threads. No one prototypes anymore. No one does their own real world testing and benchmarking. They simply Google for some docs which support their already-made decision and call it a day.

</comment><comment><USER24> Modern languages with high-level and verified async features and explicit mutability make threads much more convenient.

That paper is finally becoming dated.

</comment><comment><USER54> Async is superior. I have done processes with locks in shared memory. I have done threads. But I predict Async will slowly start to take over. Processes are not suitable for working on shared data. Threads frequently yield race conditions and deadlocks even for experienced coders. But Async doesn't have any of these issues. So why isn't it more popular? For two reasons:

1) it completely breaks the functional programming model that we all learned as toddlers (instead of call A and then, after that's done, call B, Async is call A which just installs B as a callback, returns immediately and then an "event loop" calls B). Note that promises and tasks and futures are just "syntactic sugar". Personally I'm not a fan. I don't use any of that. I just use callbacks.

2) Even though Async it's great for concurrency, it's not great for parallelism. Everything runs with one thread. So if you want parallel processing you need workers.

But I would argue that issue 1 can be overcome. In fact, I find Async to be quite elegant. I think in the long term people are going to realize that maybe we've had it backwards all along.

Issue 2 is actually not that big of a deal for most things. It's actually somewhat unusual that you need to have some CPU intensive operation running in the background. Maybe image processing, data modelling, etc. But most blocking operations are just I/O operations which are not using CPU that much. If I needed to write some kind of network server, I would look at using libuv as a portable runtime.

</comment><comment><USER55> I mean, threads are OK, but you need to essentially and artificially (because they're not processes) isolate them as much as possible (by minimizing shared state), and you want to do async/evented I/O so that you have as many threads as CPUs.

</comment><comment><USER56> Hey, I get to tell m y own two 1990's era threads story.

First: in Windows 3.1, you got exactly one thread. My former company (BBN Software Products, home of the RS/1 statistical program) managed to get a version of RS/1 on Windows by splitting it into two pieces, each of which ran a single thread. On piece (RS/Client) was the UI; it talked to the "server" using TCP/IP (or a shared memory channel if the client and server were on the same machine)

Second: I also got to help port a networking program over to an SGI box. At the time, the SGI GCC-based compiler could either supports threads, or support exceptions, but not both. (And my "unsupported" I mean, "generated code that would crash even if no exception was ever actually generated"). I couldn't convince the company to keep the threads and dump the exceptions, so instead I had to convert the program to spawn new processes with shared memory (!) to emulate the threads.

TL/DR: actually programming with threads at the time was decidedly unsupported.

<comment><USER57> True, but Windows NT 3.1 came with threads and used them throughout the kernel. They were supported by nonstandard functions in the Microsoft C runtime as well as through the windows API. Windows included its own structured exception handling facility that also worked with it.

</comment></comment><comment><USER58> This is mildly off-topic, but how does one end up working on problems that are complex enough for things like this to even be an issue? It sounds incredibly interesting to me, but most of the software I've worked on has been at least somewhat web-based.

I know there's so much more out there, and I'm just not sure how to find relevant problems to solve...it feels like a serious case of "I don't know what I don't know."

I guess I should probably just pick some non-web concept I find interesting and start making something.

<comment><USER59> Please do that as an Ask HN, I'd be interested in the responses you hopefully get.

Edit: Ah, I see that you did, an hour ago. Very good!

</comment></comment><comment><USER60> _Concurrency isn't a "nice layer over pthreads" - the most important thing is isolation - anything that mucks up isolation is a mistake.

— Joe Armstrong_

</comment><comment><USER61> I'm all for getting rid of threads, but what are you going to replace them with? Traditional functional languages may be the most obvious solution, but they're also among the most impractical of solutions. Is there anything else out there that can replace threading needs, without throwing out the book on programming? It seems like what we need hasn't been invented yet.</comment>


Millennial Men Find Work and Family Hard to Balance - <AUTHOR> http://www.nytimes.com/2015/07/31/upshot/millennial-men-find-work-and-family-hard-to-balance.html

<comment><USER2> I wonder how much of this comes from the fact that it is much harder for millennials to support a family on one wage than it was for our parents. So the equality discussed in the article is related to needing the wife to continue working which means the husband needs to shoulder more home responsibility.</comment>


Portraying the Tudors, Then and Now - <AUTHOR> https://www.wsj.com/articles/portraying-the-tudors-then-and-now-11585327925 <comment><AUTHOR> [https://archive.md/nR7TX](https://archive.md/nR7TX)

<comment><USER2> Thank you for posting this link.

<comment><AUTHOR> You're most welcome.

</comment></comment></comment><comment><USER2> Those who have had a chance to visit the Frick will remember that across mantlepiece from Holbein's Cromwell is Holbein's Thomas More.</comment>


Breaking Down the Methodology Behind Word of Mouth Marketing - <AUTHOR> http://blog.clarity.fm/breaking-down-the-methodology-behind-word-of-mouth-marketing/ <comment><USER2> "the glamour of paid advertising is a total illusion"

Not quite. What appeals about paid marketing is very simple: definable, scalable success.

"word of mouth generates more than twice the sales of paid advertising in categories as diverse as skincare and mobile phones."

While I cannot attest to this being true or false, I can say that word of paid marketing can have a very appealing success rate.

For example, after 5 years of marketing online with my own money I can say the following:

1\. 73% of all campaigns failed

2\. 22% of all campaigns that did _not_ fail became a moderately profitable success (~50-100% ROI)

3\. 5% of all campaigns became absolute smash hits, earning over their lifetimes well past many times the investment I made to find them.

(NOTE: ROI for this example means the amount invested to test & optimize the campaign at the start ($1k-$10k) as opposed to the actual ROI of earnings over time, which is entirely different)

With a 5% smash hit rate - and a 27% success rate, that is a pretty damn good risk factor. This isn't to say that word of mouth doesn't work - it most certainly does - but paid advertising definitely has its place.

If you've got your wits about you, use paid to jump start word of mouth, and capitalize on word of mouth with paid. There is a myriad of opportunity and I would not leave either one out of the mix.

</comment><comment><USER3> Total fluff piece. Word of mouth marketing? Just sounds like PR to me. And yes, depending on your product, it helps to have a personality behind it—that's just called having a brand.

<comment><USER4> The research is real. Real data. Real numbers. I've used this approach for many launches and it works. Thought I'd finally share with the world.

<comment><USER3> What research? Perhaps I have poor reading comprehension but I don't see any data. Other than hand-wavey stuff which is branding 101, I don't see any particular insights.

</comment></comment></comment><comment><USER5> Could sum this up with Steve Martin's quote from the Charlie Rose show:

        Nobody ever takes note of [my advice], because it's not
        the answer they wanted to hear. What they want to hear
        is "Here's how you get an agent, here's how you write
        a script,"... but I always say,

        "Be so good they can't ignore you."

</comment><comment><USER6> A lot of the ideas come from - [http://www.amazon.com/books/dp/1451686579](http://www.amazon.com/books/dp/1451686579)

<comment><USER4> @joshdance 100% .. Jonas Berger is a genius. Also need to give credit to Ryan Holiday [https://clarity.fm/ryanholiday](https://clarity.fm/ryanholiday) / one of the best out there re: media manipulation to amplify WOM.</comment></comment>


Codeship launches freemium model to push its Continuous Integration Service - <AUTHOR> http://gigaom.com/2014/07/15/codeship-launches-freemium-model-to-push-its-continuous-integration-service/

<comment><USER2> I'm sort of stuck on their old "Medium" plan with 300 builds/month with no project restrictions for $25. If I downgrade to the free plan then I'll have to push less commits, which kind of ruins the point of CI for me. If I need more the Circle CI $19 plan looks mighty tempting.

It's too bad, because I do love Codeship.</comment>


The Story Behind Ruby 1.9.3 Getting 36% Faster Loading Times - <AUTHOR> http://www.rubyinside.com/ruby-1-9-3-faster-loading-times-require-4927.html?utm_source=wordtwit&utm_medium=social&utm_campaign=wordtwit

<comment><USER2> This directly relates to a popular HN story from the other day: <http://news.ycombinator.com/item?id=2594668> (in the sense that the solution outlined in that story has sort of been evaded by some optimizations made by Ruby core - temporarily, hopefully).

</comment><comment><USER3> There's an old solaris rationalization: "It's not the time it takes to reboot, but how often."

<comment><USER4> Not to nit-pick your joke, but the unfortunate case in the Rails world is _very_ often. I (try to) be a good boy and run tests before every check in, as well as writing them in advance of new features. Our project has enough files that it takes ~30-40s for the environment to load.

On an average day I probably spend 30 minutes to an hour of each day waiting on environment loading, depending on the task. Big restructurings and big new features tend to take a lot of test iterations.

Now that I do the numbers my time sunk on this is simply staggering.

<comment><USER5> ouch. that makes a profound productivity regression.

/obvious

</comment></comment></comment><comment><USER6> <http://www.youtube.com/watch?v=OJ8YfstVWKs>

</comment><comment><USER7> I find this kind of performance regression and the blasé response extremely frustrating and disappointing. What could the MRI team be working on that's more important than fixing a bug that quadruples startup time for the most popular Ruby applications? This should be fixed in a quick patch to 1.9.2. There are tens of thousands of developers wasting oodles of man-hours frustrated with this. It's bad for Ruby and bad for Rails.

Why is this not the #1 priority for the MRI team?

<comment><USER8> Without knowing anything about the core ruby developers, it's possible most of them are detached from current real world ruby applications with heavy weight frameworks?

<comment><USER9> It's amusing that Rails is now considered a heavy framework. I remember writing my first Rails app with Rails 0.8. It was a tremendous breath of fresh air then. Seven years later it's the bloated incumbent.

<comment><USER10> there's always merb 1.1</comment></comment></comment></comment>


CPU runs at reduced maximum clock speed with no battery installed - <AUTHOR> https://support.lenovo.com/us/en/documents/ht075965 <comment><AUTHOR> This means that the notebook is wasting battery cycles even when it is connected to AC if you use the original adaptor.</comment>


While it defies U.S. government, Apple abides in China and reaps big rewards - <AUTHOR> http://www.latimes.com/business/technology/la-fi-apple-china-20160226-story.html <comment><USER2> As far as I know, In the US, Apple has always fully and willingly complied with legal requests for data stored on it's servers. Even in this specific controversial case, Apple handed over the relevant data to the authorities upon legal request.

Where they are drawing the line is to "break in" to their customers' devices upon legal request. As far as I can tell from this article, there is nothing to suggest that the Chinese government has ever made such a request.

It is therefore very misleading of this article to compare the requests as if they are the same and to suggest that Apple is complying with similar requests in China while denying the US government.

</comment><comment><USER3> Is anybody shocked by this, really? Tim Cook knows very well that he will suffer absolutely no penalty for grandstanding against the U.S. government; in fact, it earns him and his company nothing but good press. Meanwhile his customer base will stand by his side (even as they obediently vote to re-elect the same government that's making the demands) and the government whose electoral base is those same customers will huff and complain but in the end do nothing.

But standing up against the Chinese government? Those guys may actually _respond_ in some fashion. That principle actually carries some financial risk. Can't have that. China gives the orders and Cook's knees can't hit the ground fast enough.

</comment><comment><USER4> I wonder if the FBI might ask China to help break into the phone(s) in question.

</comment><comment><USER5> Oh sure let's downgrade the US to Chinese standards.

Apple deserves criticism for this but don't give US politicians ideas about doing what China does.

I think there are plenty congresspeople that would like to be China for a day.</comment>


Apple iMessage attachments transfer = always unencrypted connection - <AUTHOR> http://i.imgur.com/sNYb0d1.png <comment><AUTHOR> did anyone notice, that Apple iMessage attachments are always transferred unencrypted simply via Port 80?

</comment><comment><USER2> Can you elaborate?</comment>


How I Start: Haskell - <AUTHOR> http://howistart.org/posts/haskell/1 <comment><USER2> For more practical examples like this, I highly recommend the Haskell Data Analysis Cookbook [1].

After learning the basics of Haskell, having a book chock full of practical examples of things like handling CVS files, JSON, trees, graphs, machine learning, and Haskell's outstanding support for parallel computation--is a really helpful resource. The code is extremely well written; clear, concise, and readable. The author has also put the source code on GitHub for each chapter. [2]

Afterwards, to take your skills to the next level, check out Simon Marlow's Parallel and Concurrent Programming in Haskell [3]. Simon now works at Facebook, where they're using Haskell in production [4] [5].

[1] [http://www.amazon.com/Haskell-Analysis-Cookbook-Nishant- Shuk...](http://www.amazon.com/Haskell-Analysis-Cookbook-Nishant- Shukla/dp/1783286334)

[2] [https://github.com/BinRoot/Haskell-Data-Analysis- Cookbook](https://github.com/BinRoot/Haskell-Data-Analysis-Cookbook)

[3] [http://www.amazon.com/Parallel-Concurrent-Programming- Haskel...](http://www.amazon.com/Parallel-Concurrent-Programming-Haskell- Multithreaded/dp/1449335942)

[4] [https://code.facebook.com/posts/302060973291128/open- sourcin...](https://code.facebook.com/posts/302060973291128/open-sourcing- haxl-a-library-for-haskell/)

[5] [http://community.haskell.org/~simonmar/papers/haxl- icfp14.pd...](http://community.haskell.org/~simonmar/papers/haxl-icfp14.pdf)

<comment><USER3> Yes, I found the Data Analysis cookbook very helpful as well. However, it really drove home to me the need for a dataframe/Pandas-like library in Haskell... About half the code in every one of his examples was reading a CSV file, parsing it into some ad-hoc data structure etc. For very robust production apps, that can be justifiable, but for just a quick look at some data, it should just be a one-liner...

<comment><USER4> Carter is working on a numerical stack for Haskell that should make writing a pandas-esque library in Haskell pretty easy.

He can be found at [https://twitter.com/cartazio](https://twitter.com/cartazio) and in the #numerical-haskell Freenode IRC channel.

<comment><USER4> [https://github.com/sdiehl/frame](https://github.com/sdiehl/frame) and [https://github.com/ekmett/tables](https://github.com/ekmett/tables) came up in IRC as well.

</comment></comment></comment></comment><comment><USER5> Awesome article! You really cover a lot, in a short but easily digestable write-up! It might be a little fast for complete beginners though :/...

I've come to be quite happy with my current VIM setup. I'm using,

* haskellmode for _t and _T (show and insert types, respectively) [0]

* ghc-mod for integration with neco-ghc and syntastic and for running ghc check [1]

* neco-ghc [2]

* neocomplete that uses neco-ghc, for completion suggestions [3]

* syntastic for hlint checking on save [4]

[0] [https://github.com/lukerandall/haskellmode- vim](https://github.com/lukerandall/haskellmode-vim)

[1] [https://github.com/eagletmt/ghcmod- vim](https://github.com/eagletmt/ghcmod-vim)

[2] [https://github.com/eagletmt/neco-ghc](https://github.com/eagletmt/neco- ghc)

[3] [https://github.com/Shougo/neocomplete.vim](https://github.com/Shougo/neocomplete.vim)

[4] [https://github.com/scrooloose/syntastic/](https://github.com/scrooloose/syntastic/)

</comment><comment><USER6> Nicely done. I find that the most useful pedagogic tool for learning are extensively annotated non-trivial examples (with emphasis on extensively annotated).

</comment><comment><USER7> What do you think about the lens library?

I have been trying Haskell for a few weeks and this library feels strange. Also I don't really think I need the things it provides. But perhaps I just don't understand it.

<comment><USER8> Lens is difficult to get your head around. It is simultaneously a rather simple idea ("bundle getters and setters together... ") and a ridiculously sophisticated and generalized implementation ("... in every conceivable lawful way such that they all work together as they ought to!").

You probably do want lenses. Learning to use them is its own "mind blowing" experience similar to learning functional programming itself. Better, they integrate smoothly with Haskell so once you've learned them the cost of using them is quite small.

Unfortunately, learning lenses from `lens` itself is quite hard. There is some amount of training materials (shameless plug here)

        https://www.fpcomplete.com/user/tel/a-little-lens-starter-tutorial
        https://www.fpcomplete.com/user/tel/lens-aeson-traversals-prisms

but the library itself is typically targeting a proficient user far better than a new one. I'd recommend trying to implement your own lenses as a learning task. If you don't bother generalizing it as far as Ed has then the core concept is very simple. I wrote up a CodeWars task for this using the Van Laarhoven style used in `lens`, but there are even simpler forms as well.

        http://www.codewars.com/kata/54258ffb430ca2e4b5000239

<comment><USER9> There's also simpler packages, right? Targeted at having less power, but being more understandable as a result.

Was lens-family one of the simpler ones?

        https://hackage.haskell.org/package/lens-family

<comment><USER8> There are a lot of lens packages. I'd roughly split them into the "Van Laarhoven style" and the "Abstract style".

In the Abstract Style there is `data-lens` and `fclabels`. These use some kind of packaged form of (getter,setter) and require a Category instance to compose using (.). They are all mutually incompatible with one another.

In the Van Laarhoven Style are `lens`, `lens-family`, and `lens-family-core` of which the last is the simplest. These are all mutually compatible, and compose automatically using regular function composition and the Prelude version of (.), but they're somewhat hairy to see at first since they must expose their underlying type (for subtyping purposes) and that one is pretty unexpectedly weird.

I recommend using Van Laarhoven style lenses. If you really want an abstract style lens, fclabels is the best I've been told.

</comment></comment></comment></comment><comment><USER10> Great article! As a programmer yet to have tried Haskell, this was actually one of the first articles I've read about Haskell which made sense to me. I tend to have a lot easier to learn from practical examples than the more academic approach normally seen in Haskell learning material and blog posts.

<comment><USER11> This is a common pedagogical problem with Haskell. We Haskell programmers are tempted to jump right into monads and functors and stuff, but the reality is that these (really very simple) concepts can't easily be taught by analogy. Often times the best way to learn is to slog through some examples.

</comment></comment><comment><USER3> Great write up, nice dissection of a simple (but not hello world simple) app, with all the ecosystem setup, etc. Apparently he is writing a book now - looking forward to that.

I think it is very hard to understand what a "beginner" needs - I now come across tutorials that finally make a certain concept "click", however the reason might not be that that specific tutorial was great, but rather that I have already hit my head on a bunch of other tutorials and practice that "prepared me"... Howver, Chris Allen actually working on teaching Haskell to a bunch of beginners is probably a great way of understanding what helps people to 'get it' sooner.

</comment><comment><USER12> When it comes to learning something like Haskell you are caught in dilemma between two ideas - Should you learn a functional programming language for fun and because it will make you a better thinker? or should you use your existing tools / stack to build something better than you have done before. What will be the better utilization of time?

While I was more oriented to former in the past, I have been inclining to latter, lately, for the reason, that what you have built remains more obvious to show and be proud of rather than knowledge of a programming language which might not be practical to build something good for variety of reasons (not soon to say the least).

<comment><USER13> I have been learning a bit of Haskell on the side recently just for the thrill of learning something completely different to the way I'm used to writing code.

My two cents so far is that using Haskell for "Real World" applications is not practical (at least in my experience), but by writing small applications in Haskell you learn a lot, it changes how you think. In my opinion, learning Haskell makes you a better programmer.

<comment><USER4> >In my opinion, learning Haskell makes you a better programmer.

No, it makes you a more _dissatisfied_ programmer.

Dissatisfied with how poor the tools in other ecosystems are.

You can't take Haskell with you. Erik Meijer is wrong about this. You can't use monads productively in Python. You can try, but it doesn't work well.

You need Haskell. Laziness, FP, immutability, types, the whole shebang. It all hangs together in a well designed way. Not even Scala can do FP well.

[https://twitter.com/bitemyapp/status/534498324296921088](https://twitter.com/bitemyapp/status/534498324296921088)

[https://twitter.com/bitemyapp/status/534498480430284801](https://twitter.com/bitemyapp/status/534498480430284801)

[https://twitter.com/bitemyapp/status/534498423870066688](https://twitter.com/bitemyapp/status/534498423870066688)

[https://twitter.com/bitemyapp/status/534498512398864384](https://twitter.com/bitemyapp/status/534498512398864384)

[https://twitter.com/bitemyapp/status/534500037901176832](https://twitter.com/bitemyapp/status/534500037901176832)

To quote mwotton:

"here is a lightsaber, an elegant and powerful weapon. After you practice with this, you will be much better at stick-poking." is absurd.

More powerful abstractions tend to invalidate more and more combinations of terms. This means the space in which your program will be correct gets narrower and narrower.

The good news is, it means your abstractions will more precisely represent the correct program you want.

The bad news is, you'll want help from the computer and a well-designed language.

I have a video of my Haskell workflow here: [https://www.youtube.com/watch?v=Li6oaO8x2VY](https://www.youtube.com/watch?v=Li6oaO8x2VY)

It's worth considering in this context what Haskellers mean when they talk about "type tetris".

<comment><USER14> > No, it makes you a more _dissatisfied_ programmer.

Maybe it makes _you_ a more dissatistfied programmer.

> You can't take Haskell with you. Erik Meijer is wrong about this. You can't > use monads productively in Python. You can try, but it doesn't work well.

Can you explain why? Because its my experience that monads, once you understand them even a little bit, open up a way of thinking about and addressing problems that can be productively used in most programming languages (Python certainly included).

> You need Haskell. Laziness, FP, immutability, types, the whole shebang. It > all hangs together in a well designed way.

Certainly Haskell's very nice and hangs together fairly well (though its also got some warts.) And certainly, some people will be much more productive with Haskell than with other languages. But that doesn't mean that learning Haskell won't improve your productivity with other languages, and that the combination of available existing libraries, etc., might still make some other language a net win for a particular real-world project.

> Not even Scala can do FP well.

Scala is certainly less good at some things than Haskell is -- and its especially unsurprising that its not as great at FP since it deliberately compromises Haskell-style FP to support extended Java-style OO (and thereby also to interop well with Java.)

> "here is a lightsaber, an elegant and powerful weapon. After you practice > with this, you will be much better at stick-poking." is absurd.

Except its not, either in the literal sense (lightsaber fighting, after all, _is_ stick poking with SFX) or the figurative sense.

<comment><USER15> > Can you explain why? Because its my experience that monads, once you > understand them even a little bit, open up a way of thinking about and > addressing problems that can be productively used in most programming > languages (Python certainly included).

I talked about part of the answer to this question at the New York Haskell Meetup awhile back.

[http://vimeo.com/59215336](http://vimeo.com/59215336)

<comment><USER14> The criticism there doesn't seem to be about _why_ static typing is particularly a bar to productive use of monads, just the general criticism that dynamic languages lack type safety, and so limit you to monadic operations without the safety of static languages. It also makes the mistake of asserting that, because dynamic languages lack enforced types, the _definition_ of a monad is different in those languages is different. But the definition of a monad is the same -- and includes the Monad Laws as well as the signatures of the bind and return (or fmap and join) functions -- independent of language. And the monad laws -- which even Haskell can't enforce for user-defined monads -- are just as important to correct monad use as the type signatures of the bind/return functions. Enforcement of essential properties is _useful_ , but its not essential to productive use _as the use of Monads in Haskell itself demonstrates_.

Its manifestly clear that productive programming without type safety is possible, and I don't see anything there that distinguishes why that would be _less_ true with monads.

</comment></comment></comment></comment></comment></comment><comment><USER16> Nice article.

As of lately, I've been using a bundled GHC app for OSX development. Makes it quite easy to keep (and switch between) multiple Haskell environments.

[http://ghcformacosx.github.io/](http://ghcformacosx.github.io/)

<comment><USER17> Not sure if you caught this, but that's what Chris Allen is linking to on this page [http://new-www.haskell.org/downloads/osx](http://new- www.haskell.org/downloads/osx)

Also, that app is great. Really nice that it comes with Cabal 1.20 .

<comment><USER16> Oh.

IIRC, haskell.org used to point to a download of the Haskell Platform for OSX (definitely not to ghc.app at any rate), so when I saw that's where it pointed, I didn't even notice that they'd changed it.

<comment><USER18> The link for OSX points to `new-www`.haskell.org. I'm sure the old site still links to haskell platform.

</comment></comment></comment></comment><comment><USER19> For me, the lectures from Nishant Shukla were really helpful: [http://shuklan.com/haskell/](http://shuklan.com/haskell/)

</comment><comment><USER20> This is a great, well-written article. I'm going to try it out later tonight. Hopefully going through a real-life example will make LYAH a little less cryptic.

</comment><comment><USER21> I like the How I Start serie.On the other hand,while I get that languages have their specificities,I'd like the same project to be implemented in all these languages,to be able to get a quick understanding about how working with these languages feels like.

You know like a TodoMVC ,but in form of tutorial around the same project,a webapp for instance,which would require as little library as possible.

<comment><USER22> I'm the auhtor of the Erlang article on How I Start. I've felt the same in some ways because it would offer a nice comparison point, but the problem with this idea is that it doesn't let the authors pick a problem for which they think their tool shines.

In a way, forcing the same problem on all authors is more or less risking telling them "you may have to use the wrong tool for this job, but please tell us how you'd do it."

Instead, I think the current format is, well first of all nicer for the author (they can pick what inspires them), and also gives you a richer level of content where you may end up learning more than you thought you would.

For example, the Erlang text focuses on Releases and shipping Erlang systems, something I felt was still blurry in a lot of people's minds. the Elixir project is done with a concurrent approach that wouldn't necessarily carry over the same way in Ruby, and Ruby's text is showing how to build a gem.

Letting the authors pick their subject means they can choose to focus as much as possible on what they feel is trickier with their tool of choice, rather than just showing a given program, for which a site like rosettacode.org might be more interesting.

<comment><USER23> Odd, I think I disagree with you _because_ of the convenience to the author. Especially in regards to how things extend to other problems. Or any costs in building a solution.

</comment></comment></comment><comment><USER24> This is a good series. Very few tutorial mention the dev environment setup.

It would be great if this can be complemented with a list of projects along with the unit/integration test cases (only description) that the end-system should pass along with a cloud deployment specification. There could be advanced section that encourages discovering edge cases.

When one wants to practice they can slowly climb the ladder to understand how to implement a system and gain expertise. I always find myself lacking in ideas on how to practice what I know. Practising the same set of data structures and algorithms is not very motivating.

</comment><comment><USER25> Very interesting! Is there something like this for other languages / frameworks? I'd love to see something like this for Ruby + Sintara + MySQL/PostgerSQL for writing a RESTful API setup.

<comment><USER26> Sorry if this isn't what you're asking, but this article is part of a series for different languages: [http://howistart.org/](http://howistart.org/)

</comment></comment><comment><USER27> This is a really great idea and series. Looking forward to more.</comment>


Firefox extensions to make remote work and school a little better - <AUTHOR> https://blog.mozilla.org/firefox/firefox-extensions-work-from-home/ <comment><USER2> I didn't see multi-account containers mentioned:

[https://github.com/mozilla/multi-account- containers#readme](https://github.com/mozilla/multi-account-containers#readme)

That one changed my life. It allows me to log into different AWS accounts at the same time. Also different Gmail accounts at once (like my kids' email and mine).

Also it gives you a massive boost in privacy since cookies don't follow you around since they are restricted to one container.

Combined with Container Tabs Sidebar:

[https://github.com/maciekmm/container-tabs- sidebar](https://github.com/maciekmm/container-tabs-sidebar)

You get the tree style tabs with automatic organization by container.

<comment><USER3> I stil think profiles (personas in chrome) are better and more flexible. I can completely have different browsers, extensions, themes, for different contexts. This beats containers for me.

Firefox --no-remote

<comment><USER4> One significant advantage of the Firefox model is the ability to bind domains to a container. I cannot open my Internet Banking in the same container as the hacking forums I might frequent, it will automatically launch in the correct container. I use Chrome personas a lot (I have 8 on the go currently) because, frankly I like Chrome more, but container URL isolation is a better implementation of workload isolation. IMHO. I'm constantly opening URLs in the wrong container because I just ctrl+T and start typing.

Actually you've inspired me to use a 'timewaster' blocking extension to prevent some URLs from loading in my main personas. Might achieve the same thing.

<comment><USER5> I've created a little app for myself that opens the right (Firefox) profile when another application tries to start the browser. It's registered as the default browser so it handles all the cases.

I guess I could also write a userscript that handles the links being opened from the browser itself. Like the timewaster extension you mentioned but also starts the right instance in background.

<comment><USER6> That sounds as a good idea, how does that script look like?

<comment><USER5> Simple command line program that looks at its arguments and decides what browser to open. Nothing fancy.

</comment></comment></comment></comment></comment></comment><comment><USER7> I can't describe in short how Tree Style Tab improves tab management.

* You can logically organize tabs, very valuable when you researching something, or when you work on multiple related web pages. Say, issue tracker, a PR or two github for this issue, a couple of doc pages related to the code, etc. The beauty of it is that the tabs mostly self-organize based on the opening order.

* You can expand and contract whole subtrees to keep current things in focus, and other things, readily available.

* You can have 30 or 50 tabs and still actually read the captions of the tabs!

* You can bookmark the whole subtree, or move it to a separate window, or close all of its tabs, or refresh all of its tabs, etc.

<comment><USER8> I love tree style tabs but it takes up _a lot_ of horizontal screen real estate. It's great when my browser is in fullscreen but most of the time I have a terminal on the right half with my browser on the left. This winds up smooshing the actual website to switch to a mobile layout (if I'm lucky). Otherwise the website is rendered useless.

Is it possible to make the sidebar float atop the webpage instead of pushing the content in? Then perhaps it could quickly autohide as you move your cursor near it.

<comment><USER9> My issue is that you can't disable the default tab bar, so you end up wasting a lot of space by rendering each tab twice. It also makes the habit (of using the default horizontal tabs) a tough one to break.

<comment><USER10> Of course you can.

about:profiles

root directory → open directory

create a new file `chrome/userChrome.css` and put this into it:

        #main-window[tabsintitlebar="true"]:not([extradragspace="true"]) #TabsToolbar > .toolbar-items {
            opacity: 0;
            pointer-events: none;
        }

        #main-window:not([tabsintitlebar="true"]) #TabsToolbar {
            visibility: collapse !important;
        }

        #sidebar-header {
            display: none;
        }

        toolbarbutton#alltabs-button {
            -moz-binding: url(data:text/plain;charset=utf-8;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+DQo8IS0tIENvcHlyaWdodCAoYykgMjAxNyBIYWdnYWkgTnVjaGkNCkF2YWlsYWJsZSBmb3IgdXNlIHVuZGVyIHRoZSBNSVQgTGljZW5zZToNCmh0dHBzOi8vb3BlbnNvdXJjZS5vcmcvbGljZW5zZXMvTUlUDQogLS0+DQoNCjwhLS0gUnVuIHVzZXJDaHJvbWUuanMvdXNlckNocm9tZS54dWwgYW5kIC51Yy5qcy8udWMueHVsLy5jc3MgZmlsZXMgIC0tPg0KPGJpbmRpbmdzIHhtbG5zPSJodHRwOi8vd3d3Lm1vemlsbGEub3JnL3hibCI+DQogICAgPGJpbmRpbmcgaWQ9ImpzIj4NCiAgICAgICAgPGltcGxlbWVudGF0aW9uPg0KICAgICAgICAgICAgPGNvbnN0cnVjdG9yPjwhW0NEQVRBWw0KICAgICAgICAgICAgICAgIGlmKHdpbmRvdy51c2VyQ2hyb21lSnNNb2QpIHJldHVybjsNCiAgICAgICAgICAgICAgICB3aW5kb3cudXNlckNocm9tZUpzTW9kID0gdHJ1ZTsNCg0KICAgICAgICAgICAgICAgIHZhciBjaHJvbWVGaWxlcyA9IEZpbGVVdGlscy5nZXREaXIoIlVDaHJtIiwgW10pLmRpcmVjdG9yeUVudHJpZXM7DQogICAgICAgICAgICAgICAgdmFyIHh1bEZpbGVzID0gW107DQogICAgICAgICAgICAgICAgdmFyIHNzcyA9IENjWydAbW96aWxsYS5vcmcvY29udGVudC9zdHlsZS1zaGVldC1zZXJ2aWNlOzEnXS5nZXRTZXJ2aWNlKENpLm5zSVN0eWxlU2hlZXRTZXJ2aWNlKTsNCg0KICAgICAgICAgICAgICAgIHdoaWxlKGNocm9tZUZpbGVzLmhhc01vcmVFbGVtZW50cygpKSB7DQogICAgICAgICAgICAgICAgICAgIHZhciBmaWxlID0gY2hyb21lRmlsZXMuZ2V0TmV4dCgpLlF1ZXJ5SW50ZXJmYWNlKENpLm5zSUZpbGUpOw0KICAgICAgICAgICAgICAgICAgICB2YXIgZmlsZVVSSSA9IFNlcnZpY2VzLmlvLm5ld0ZpbGVVUkkoZmlsZSk7DQoNCiAgICAgICAgICAgICAgICAgICAgaWYoZmlsZS5pc0ZpbGUoKSkgew0KICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJub25lIjsNCiAgICAgICAgICAgICAgICAgICAgICAgIGlmKC8oXnVzZXJDaHJvbWV8LnVjKS5qcyQvaS50ZXN0KGZpbGUubGVhZk5hbWUpKSB7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJ1c2VyY2hyb21lL2pzIjsNCiAgICAgICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgaWYoLyhedXNlckNocm9tZXwudWMpLnh1bCQvaS50ZXN0KGZpbGUubGVhZk5hbWUpKSB7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJ1c2VyY2hyb21lL3h1bCI7DQogICAgICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgICAgICBlbHNlIGlmKC8uYXMuY3NzJC9pLnRlc3QoZmlsZS5sZWFmTmFtZSkpIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gImFnZW50c2hlZXQiOw0KICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZigvXig/ISh1c2VyQ2hyb21lfHVzZXJDb250ZW50KS5jc3MkKS4rLmNzcyQvaS50ZXN0KGZpbGUubGVhZk5hbWUpKSB7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJ1c2Vyc2hlZXQiOw0KICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgICAgICAgICAgaWYodHlwZSAhPSAibm9uZSIpIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygiLS0tLS0tLS0tLVwgIiArIGZpbGUubGVhZk5hbWUgKyAiICgiICsgdHlwZSArICIpIik7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJ5IHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYodHlwZSA9PSAidXNlcmNocm9tZS9qcyIpIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNlcnZpY2VzLnNjcmlwdGxvYWRlci5sb2FkU3ViU2NyaXB0V2l0aE9wdGlvbnMoZmlsZVVSSS5zcGVjLCB7dGFyZ2V0OiB3aW5kb3csIGlnbm9yZUNhY2hlOiB0cnVlfSk7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZih0eXBlID09ICJ1c2VyY2hyb21lL3h1bCIpIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHh1bEZpbGVzLnB1c2goZmlsZVVSSS5zcGVjKTsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIGlmKHR5cGUgPT0gImFnZW50c2hlZXQiKSB7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZighc3NzLnNoZWV0UmVnaXN0ZXJlZChmaWxlVVJJLCBzc3MuQUdFTlRfU0hFRVQpKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNzcy5sb2FkQW5kUmVnaXN0ZXJTaGVldChmaWxlVVJJLCBzc3MuQUdFTlRfU0hFRVQpOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgaWYodHlwZSA9PSAidXNlcnNoZWV0Iikgew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYoIXNzcy5zaGVldFJlZ2lzdGVyZWQoZmlsZVVSSSwgc3NzLlVTRVJfU0hFRVQpKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNzcy5sb2FkQW5kUmVnaXN0ZXJTaGVldChmaWxlVVJJLCBzc3MuVVNFUl9TSEVFVCk7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGNhdGNoKGUpIHsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coIiMjIyMjIyMjIyMgRVJST1I6ICIgKyBlICsgIiBhdCAiICsgZS5saW5lTnVtYmVyICsgIjoiICsgZS5jb2x1bW5OdW1iZXIpOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygiLS0tLS0tLS0tLS8gIiArIGZpbGUubGVhZk5hbWUpOw0KICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbiBsb2FkWFVMKCkgew0KICAgICAgICAgICAgICAgICAgICBpZih4dWxGaWxlcy5sZW5ndGggPiAwKSB7DQogICAgICAgICAgICAgICAgICAgICAgICBkb2N1bWVudC5sb2FkT3ZlcmxheSh4dWxGaWxlcy5zaGlmdCgpLCBudWxsKTsNCiAgICAgICAgICAgICAgICAgICAgICAgIHNldFRpbWVvdXQobG9hZFhVTCwgNSk7DQogICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICB9LCAwKTsNCiAgICAgICAgICAgIF1dPjwvY29uc3RydWN0b3I+DQogICAgICAgIDwvaW1wbGVtZW50YXRpb24+DQogICAgPC9iaW5kaW5nPg0KPC9iaW5kaW5ncz4=);
        }

restart the browser

It also removes some other junk like the new tab button.

<comment><USER11> Thanks this is very useful!

Note: To enable userChrome reading, set

      toolkit.legacyUserProfileCustomizations.stylesheets

to true in

      about:config

<comment><USER12> Thank you for the update on the instructions, but its still not working in Firefox. Anything else I can try or need to do?

</comment></comment></comment></comment></comment></comment><comment><USER13> > LanguageTool: By default, this extension will check your text by sending it > to [https://languagetool.org](https://languagetool.org) over a securely > encrypted connection. No account is needed to use this extension. We don't > store your IP address.

Honestly I'd pay good money if someone invented a competitor to this, Grammerly, or Ginger that was all local (an actual usage for machine learning/NLP!). It doesn't need to be perfect just better than the bad spelling/grammar solution built into Firefox, and more private than these services.

<comment><USER14> Here is how you run your own languagetool server :]

[http://wiki.languagetool.org/http-server](http://wiki.languagetool.org/http- server)

<comment><USER13> Thanks giving that a shot now.

Edit: Alright this is pretty good. I'm going to stick with this for a while. It was super easy to get up and going (just spawn with "start javaw" for a background daemon).

I installed the 14 GB n-gram data too, which makes it even better. Only tip is that the command line arguments are case specific for some reason (languagemodel vs languageModel matter).

<comment><USER15> Don't forget to give the creators the "good money" you promised :) [https://languagetool.org/#Price](https://languagetool.org/#Price)

</comment></comment></comment></comment><comment><USER16> A few of these have the "Access your data for all websites" permission and honestly, I can't shake the feeling that I'm giving away all data on all websites at all times if I install any of these

<comment><USER17> As an extension developer, I hate to say it, but you're absolutely right to feel that way. I've had people offer to pay me to put tracking or buy an extension outright, and my extensions aren't even that popular; I can only imagine what emails developers of extensions with 100k+ users get.

If anyone from Firefox is reading these, I'd love a way to link an extension to a Github repository with a particular hash, and have users be able to verify that the code in the extension actually matches what's in the repo. Currently, even if an extension "lives" on GitHub, there's no way to know that what's in the extension library matches what's on Github.

<comment><USER18> That's terrifying. Is there any auditing done by Mozilla to get an extension published? Or is it a free for all?

<comment><USER17> To their credit, Mozilla does have an approval process, but it's pretty opaque what actually happens during that process. They also have a "Recommended Extensions" program which does more thorough vetting, apparently. Chrome is more of a free-for-all.

<comment><USER19> > Chrome is more of a free-for-all

Chrome is very strict, as of the last several months, about what they allow. There's even a sticky in the support group for people whose extensions have been stuck in review for more than 3 weeks:

[https://groups.google.com/a/chromium.org/forum/?utm_medium=e...](https://groups.google.com/a/chromium.org/forum/?utm_medium=email&utm_source=footer#!forum/chromium- extensions)

</comment></comment></comment></comment></comment><comment><USER20> May I humbly suggest [https://histre.com/](https://histre.com/) that I'm building?

Not only can you bookmark and take notes, you can share collections of bookmarks with your teams and they can add theirs to the collection too.

You can save all the open tabs in a browser window into a collection and either use it to restore that window later - perhaps even in a different browser or computer, or share that with your teams so they can open the same set of tabs.

It has tree style web history too.

The disjointed suggestions they have in this post is actually fully integrated in Histre, Emacs-style if you will. The core idea is that you generate a lot of signal as you go about your day doing stuff online and that can automatically be put to use for you. Unlike the Knowledge Bases like Notion and Evernote, where you need to capture and organize the information (which is useful in a different way), Histre strives to automatically organize it for you.

I'd argue that this supports the "remote work and school" usecase better.

Speaking of integrations, it has Hacker News integration too. Your upvotes are saved into a collection. You can then share that collection with just some friends or make it public (sort of your frictionless publishing page). I'm working on recommending articles based on your HN upvotes.

<comment><USER21> I created an account and then I was asked for my credit card details for a 30 day trial. I declined to do so and went to the home page where I was invited to install an extension.

I clicked on the Firefox logo and it was a broken link so I can't really give this a ride.

<comment><USER20> Hey really sorry about that, bad timing. I got an email from a Firefox reviewer this morning asking me to remove the uses of innerHTML. I'm working on fixing that. It is taking a little while because of how I use it in Quill ([https://quilljs.com/](https://quilljs.com/)). I'll send you an email once it is fixed. The extension is open source by the way: [https://gitlab.com/histre/browser- extension](https://gitlab.com/histre/browser-extension)

</comment></comment></comment><comment><USER22> I'll vouch for Tree Style Tabs. It's a killer extension that changed the way I work and made Firefox into a serious productivity workhorse for me. I can easily manage 10x as many tabs as I could before without ever feeling like I'm getting lost in them.

<comment><USER21> I've been using TST for a while now but this week I have found new improvements.

I have started using Simple Tab Groups rather than OneTab and I have customised the CSS in userChrome.css and now have a slimmer sidebar that expands on hover.

Gif here: [https://postimg.cc/xJ2jfFGx](https://postimg.cc/xJ2jfFGx)

Edit: here's the repo where I got the expand TST on hover style [https://github.com/TanzNukeTerror/Compact- FirefoxCSS/](https://github.com/TanzNukeTerror/Compact-FirefoxCSS/)

<comment><USER23> This is sweet, cheers! I played around off the back of this to get a bit of a hybrid going - pinned / active tabs up top and grouped / standard tabs down the side: [https://gist.github.com/theprojectsomething/6813b2c27611be03...](https://gist.github.com/theprojectsomething/6813b2c27611be03e67c78d936b0f760)

</comment></comment></comment><comment><USER24> uBlock Origin needs to be on the list. It doesn't make remote work or school better, specifically, but it makes the whole web great (again).

<comment><USER25> yes - new computer/device for anyone in the family => install uBO. I've only had one complaint abouty a site that no longer worked properly (and it was both (a) garbage and (b) targeting kids specifically)

</comment></comment><comment><USER26> If you want to be more intentional about how you use your time online, I launched Intention on HN a little while ago:

[https://getintention.com](https://getintention.com)

Spent a lot of time getting privacy right: It only asks you for the sites you select (not all sites like most other extensions).

HN thread: [https://news.ycombinator.com/item?id=22936742](https://news.ycombinator.com/item?id=22936742)

<comment><USER27> Intention is awesome.

I had a habit of unknowingly typing "g" in my Chrome's search bar and visit G1 (a Brazil's news site). It became something I just did that on a whim, multiple times along the day, and now Intention is saving me almost 50 minutes of productivity every day.

<comment><USER28> I just found your comment on another thread where you said that you wanted to find Ira Glass's video on "taste" but now it's been long enough that I can't reply to that comment, so I'm replying to this completely unrelated comment because I've also had trouble finding that video in the paste and decided to save the link the last time I found it.

Here it is: [https://vimeo.com/85040589](https://vimeo.com/85040589)

</comment></comment></comment><comment><USER29> I've found switching the user agent to Chrome to be the most effective solution for ensuring sites and platforms operate as expected, without degregaded experience.

Yes, this includes non-Google educational platforms that block access based on user agent (not compatibility)

</comment><comment> 867-5309 If my kids are on Windows laptops I can use Microsoft Family settings to control OS lockout, app access and Edge restrictions.

If they're on tablets I can use Google Family for a similar experience with Android and Chrome.

If they're on Kindle Fires then Amazon offer similar Family settings.

OS aside, what does Firefox have to offer in this respect?

<comment><USER30> What's wrong with OS level control? Your kids can install alternative browser.

<comment> 867-5309 Windows can only control Edge, so all other browsers have to be blocked. same story with other OSes and their respective browsers

<comment><USER31> What kind of restrictions are we talking about?

</comment></comment></comment></comment><comment><USER32> I'd like to offer a recommendation for Zoom Tab Close[1]. It's an extremely simple extension that closes out the leftover tab when a zoom link received by the browser redirects to the desktop app. Just one bit of friction in my day ... gone.

[1] [https://addons.mozilla.org/en-US/firefox/addon/zoom-tab- clos...](https://addons.mozilla.org/en-US/firefox/addon/zoom-tab-close/)

</comment><comment><USER33> When I switched to Firefox, I found the lack of pop-up styled Google Dictionary to be a deal-breaker. So I created an extension - [https://addons.mozilla.org/en-US/firefox/addon/popup- encyclo...](https://addons.mozilla.org/en-US/firefox/addon/popup- encyclopedia/). It supports both the dictionary and encyclopedia words. Students may find this extension useful.

</comment><comment><USER34> We're releasing our extension soon for all browsers.

[https://forwardemail.net](https://forwardemail.net)

Here's extensions I use and my full setup: [https://gist.github.com/niftylettuce/39597a7b3bc0660ffe1e09d...](https://gist.github.com/niftylettuce/39597a7b3bc0660ffe1e09d77588bcf6)

        git clone https://github.com/zenorocha/codecopy
        git clone https://github.com/philc/vimium.git
        git clone https://github.com/OctoLinker/OctoLinker.git
        git clone https://github.com/ilGur1132/Smart-HTTPS.git
        git clone https://github.com/ovity/octotree.git
        git clone https://github.com/mrcoles/full-page-screen-capture-chrome-extension.git

\+ [https://github.com/jswanner/DontFuckWithPaste](https://github.com/jswanner/DontFuckWithPaste) \+ [https://github.com/gorhill/uBlock](https://github.com/gorhill/uBlock)

</comment><comment><USER35> Panorama Tab Groups is the best replacement for the old Tab groups extension : [https://addons.mozilla.org/en-US/firefox/addon/panorama- tab-...](https://addons.mozilla.org/en-US/firefox/addon/panorama-tab-groups/)

I resisted upgrading for ages while there didn't seem to be a clear winning replacement.

<comment><USER36> Thank you so much for sharing this! I used Panorama so intensively and thought it was one of Fx's killer features. I'd given up hoping there would be a suitable replacement - until now.

</comment></comment><comment><USER37> I'm unfamiliar with the Dark Mode extensions referenced in this article, but I've had pretty good luck with Dark Reader.

It's not as performant on Firefox as on Chrome (and it really shows in Gmail in particular) but overall it's been very reliable and easy to customize when necessary.

</comment><comment><USER38> My favorite extension is the "Tab reloader". I can set it to reload my work login page and it won't expire my session.

And uBlock Origin and Tree Tab are fundamental for the web. Containers also nice, I can login at sites like Trello and GitHub with different accounts.

</comment><comment><USER39> Humbly suggesting BeeLine Reader for Chrome [1] and Firefox [2], which has seen a strong uptick in interest during WFH and distance learning. There's a 2-week free trial, and it's currently free for students via our covid program.

1: [https://chrome.google.com/webstore/detail/beeline- reader/ifj...](https://chrome.google.com/webstore/detail/beeline- reader/ifjafammaookpiajfbedmacfldaiamgg?hl=en)

2: [https://addons.mozilla.org/en- US/firefox/addon/beelinereader...](https://addons.mozilla.org/en- US/firefox/addon/beelinereader/)

<comment><USER40> I've tried Beeline multiple times and I every time I come out with varying experiences. For example it's pretty much useless for reading code stuff as it colors in code blocks with no way to disable that.

Also I'm certain it actually makes well formatted text harder to read. As in 60-70 character lines with healthy paragraphing and imagery.

I'm kinda perplexed that they are charging 2$/month for this extension when it could be replicated in javascript bookmarklet or grease monkey script. All it does is blindly apply gradient to text.

Not a fan of accessibility innovations like this being made propriatory like this either.

<comment><USER39> You're right about code blocks! We offer a domain blacklist feature so that folks can prevent it from running on sites they read that have a lot of code, and we are working on a smarter way to detect code blocks and not color them.

If you're certain that BeeLine "makes well formatted text harder to read", then I'm pretty sure we're not for you! I'd be curious to know where you find it helpful? Just for text that is displayed too densely?

We're doing a bit more than blindly applying gradients to text! The first thing to figure out is where the body text is on a page. It's not easy to avoid overcoloring (accidentally coloring captions or text that is on a different-colored background) and undercoloring (not coloring all of the main blocks of text). It's easy to do these tasks on a handful of websites, but it's hard to come up with algorithms that work across the entire internet (in many languages). But yes, what we do is something that is proprietary, and that makes it different than some accessibility techniques. There are other aspects of accessibility that are proprietary, for example high-quality TTS voices like Amazon Polly.

But my goal is to have the technique that I invented, tested, and refined adopted into products so that users do not have to pay for plugins and such. There's good progress on this front, with major e-textbook platforms and big newspapers looking to integrate the tech. Once we get a couple of these larger licensees on board, there's a good chance we'll make the consumer tools free for individuals.

<comment><USER40> sorry to put you on the spot but what makes it difficult to simply ignore `\<pre>` blocks?

As to answer your question - beeline is great for _badly_ formatted texts. Many articles are in whooping 120 character long lines or absurdly long, bland paragraphs. In those cases the benefit of beeline is definitely noticable!

Finally for technical bits, it seems that that beeline extension colors each letter individually, however modern css already offers horizontal gradient[1] which might be prettier and somewhat preserve the original document better.

[https://stackoverflow.com/questions/39884260](https://stackoverflow.com/questions/39884260)

<comment><USER39> Thanks for the advice! The last item is the most important I think, and the reason we didn't originally do this is because the plugin has been cross- platform since launch in 2013. I believe at that time the CSS technique only worked on certain browsers. We have been talking about updating the coloring technique to use CSS, but it hasn't been a top priority compared to everything else we've been doing (both on the browser plugin and on the rest of the business).

I'm going to talk with the team about your suggestion regarding \<pre> blocks. We're early in the process of addressing this issue, which has come up recently. Hope it's a quick fix!

</comment></comment></comment></comment></comment><comment><USER41> If you don't use tree style tabs to browse the web, you're probably doing it wrong.

<comment><USER42> Was using it extensively, have customised it with userchrome file.

But then went to idea of having fewer tabs open and only w.r.t context I'm working on. Lesser number of tabs made things much more simpler for me.

Have been both sides, and must way for people with lots of tabs, tree style tabs is seriously good.

<comment><USER43> I did the same. I was relying on tree style tab heavily and kept 30-40 tabs opened all the time. Obviously without the extension this would be a pain.

But then I realized that most tabs I have opened hang there for weeks and months without me even looking at them, occupying screen and mental space. Now I made a simple habbit: once I've read the tab and don't need it right now, I just close it. Should I need to return to it later, it's trivial to re-open it from history.

One might think it's kind of a konmari approach, and when you're doing it you don't need extra management tools anymore.

</comment></comment></comment><comment><USER44> Since we're talking about extensions, can I suggest my own Tip Tab [1] for visually navigate and manage tabs? Just updated it after a year of break. I mostly use it for quick search and keyboard navigation (ctrl-shift-F, type search term, Tab Tab Tab Enter to jump to the tab). Also use the predefined search terms like, mail, news, finance, etc, to quickly filter down the tabs.

[1] [https://addons.mozilla.org/en-US/firefox/addon/tip- tab/](https://addons.mozilla.org/en-US/firefox/addon/tip-tab/)

<comment><USER45> Suggest mine Tab Manager v2 too: it has VIM-like navigation (hjkl) and other features can be searched via Command+Shift+P. And Command+T (Alt+T for non- macOS) to toggle the popup window:

[https://addons.mozilla.org/en-US/firefox/addon/tab- manager-v...](https://addons.mozilla.org/en-US/firefox/addon/tab-manager-v2/)

</comment></comment><comment><USER46> I use Sidebery for tab management and find it more lightweight than Tree Style Tab

[https://addons.mozilla.org/en- US/firefox/addon/sidebery/](https://addons.mozilla.org/en- US/firefox/addon/sidebery/)

And LeechBlock NG has massively helped me gain back my wasted time browsing the web

[https://addons.mozilla.org/en-US/firefox/addon/leechblock- ng...](https://addons.mozilla.org/en-US/firefox/addon/leechblock-ng/)

<comment><USER47> Wow, this is awesome. Much more responsive than Tree Style Tabs from what I'm seeing, and the grouping mechanism is great. Thanks for the heads up.

</comment></comment><comment><USER48> I wish they would let you hide Firefox accounts behind passwords so the browser just looks vanilla when you sign out. Rather it leaves bookmarks behind.

Makes it hard to use with sharing devices like an iPad and etc.

<comment><USER49> Does iOS not have user accounts? Every other OS has this and it makes this feature useless.

<comment><USER48> iPads behave as single user device, so they don't allow for multi users at the OS level.

Personally I'd prefer both Firefox and iOS support multi user things ... even if just for my own convenience. I have "work" and "home" type profiles.

</comment></comment></comment><comment><USER50> I still miss the mouse gesture extensions from the pre-Web Extensions days. The suggested replacements only work on a loaded webpage, which limits their use as a replacement to keyboard shortcuts, especially when combined with a tab unloader extension[1].

[1] such as [https://addons.mozilla.org/en-US/firefox/addon/auto-tab- disc...](https://addons.mozilla.org/en-US/firefox/addon/auto-tab-discard/)

</comment><comment><USER51> Learned about midnight lizard thanks to this post. like it a lot. some websites take a while till they are rendered in midnight mode. However, my laptop is not very powerful.

</comment><comment><USER52> speed dials! this one is open source and privacy conscious (i'm the author):

[https://addons.mozilla.org/en-CA/firefox/addon/yet- another-s...](https://addons.mozilla.org/en-CA/firefox/addon/yet-another- speed-dial/)

</comment><comment><USER53> Simple tab groups it's a game changer. At least, I can have separate my tab setup when I'm working, from the stuff that I have open when I'm with my side projects, or when I simply doing other unrelated stuff.

<comment><USER53> Also, the Private bookmarks, was a thing that I was feeling very necessary like many years ago. It isn't perfect (alpha stage) but does the work.

</comment></comment><comment><USER54> The joplin extension and application.

([https://joplinapp.org/](https://joplinapp.org/) \- next cloud syncing functionality baby!)

Duplicate tabs closer

</comment><comment><USER55> > Impulse Blocker is here to keep you away from those distracting, timesink > websites

... which are the primary use case for Firefox (and all other web browsers.)

</comment><comment><USER56> These maybe / are great features and extensions, but I don't see what any of them have to do with WFH?

</comment><comment><USER57> It's a good time for companies based on improving remote work/school...

</comment><comment><USER58> I fail to see how is this related to remote work and not just work in general. Does firefox really need this this kind of "jump on the hype" kind of marketing ?</comment>


HP's first Android tablet is $169 and will be at Mobile World Congress - <AUTHOR> http://arstechnica.com/gadgets/2013/02/hps-first-android-tablet-is-169-and-will-be-at-mobile-world-congress/

<comment><USER2> I haven't been keeping up with the news (if there was any news...) but this suggests that WebOS is now completely dead.</comment>


Useful Online Generators for Designers - <AUTHOR> http://www.balkhis.com/web-designs-resources/55-extremely-useful-online-generators-for-designers/

<comment><USER2> Wow, XML/SWF Charts may have just saved my life, I don't know for sure, but it's definitely a possibility.

</comment><comment><USER3> Tartan Maker. Priceless!</comment>