<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Untitled Publication]]></title><description><![CDATA[Untitled Publication]]></description><link>https://blog.marcoromano.net</link><generator>RSS for Node</generator><lastBuildDate>Sun, 10 May 2026 08:21:53 GMT</lastBuildDate><atom:link href="https://blog.marcoromano.net/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to massively rename directories in a project]]></title><description><![CDATA[I recently had to change the package name of a project I'm working on but somehow the IDE didn't manage to adjust the name of the directories accordingly.
Turns out there's a command line utility called rename that can be helpful in such situations.
...]]></description><link>https://blog.marcoromano.net/how-to-massively-rename-directories-in-a-project</link><guid isPermaLink="true">https://blog.marcoromano.net/how-to-massively-rename-directories-in-a-project</guid><category><![CDATA[rename]]></category><dc:creator><![CDATA[Marco Romano]]></dc:creator><pubDate>Tue, 14 Mar 2023 13:09:26 GMT</pubDate><content:encoded><![CDATA[<p>I recently had to change the package name of a project I'm working on but somehow the IDE didn't manage to adjust the name of the directories accordingly.</p>
<p>Turns out there's a command line utility called <code>rename</code> that can be helpful in such situations.</p>
<p>You can install it with your favorite package manager e.g.</p>
<pre><code class="lang-bash">brew install rename
</code></pre>
<p>And then you can use it as such:</p>
<pre><code class="lang-bash">find ./ -<span class="hljs-built_in">type</span> d -name oldname -execdir rename <span class="hljs-string">'s/oldname/newname/g'</span> <span class="hljs-string">'{}'</span> \+;
</code></pre>
<p>This will use the <code>find</code> command to find all subdirectories of the current directory named "oldname" and then will execute the <code>rename</code> command to rename each of them from "oldname" to "newname".</p>
]]></content:encoded></item><item><title><![CDATA[Approaching your first remote job]]></title><description><![CDATA[A lot of contract and employment considerations you might want to think about before starting to look for a remote job.
Photo by Susanna Marsiglia on Unsplash
Acknowledgments: If you can read this article it’s because Stefano Magni has been more than...]]></description><link>https://blog.marcoromano.net/approaching-your-first-remote-job</link><guid isPermaLink="true">https://blog.marcoromano.net/approaching-your-first-remote-job</guid><dc:creator><![CDATA[Marco Romano]]></dc:creator><pubDate>Mon, 09 Mar 2020 15:04:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1632308578407/mxrPd8Yqs.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A lot of contract and employment considerations you might want to think about before starting to look for a remote job.</p>
<p><img src="https://cdn-images-1.medium.com/max/5400/1*ITXICvunYdp1ZgnyO_MoqQ.png" alt="Photo by [Susanna Marsiglia](https://cdn.hashnode.com/res/hashnode/image/upload/v1632308576868/9kTJ9xU--.html) on [Unsplash](https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText)" /><em>Photo by <a target="_blank" href="https://unsplash.com/@sushimi?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Susanna Marsiglia</a> on <a target="_blank" href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></em></p>
<p><em>Acknowledgments: If you can read this article it’s because <a target="_blank" href="https://twitter.com/NoriSte">Stefano Magni</a> has been more than supportive from its inception to its publication. Kudos to him!</em></p>
<p>Chances are if you’re reading this you might already be working in software development or be interested in working in the field.
Software is great and it’s for sure a sector of the world’s economy that is growing and will <a target="_blank" href="https://a16z.com/2011/08/20/why-software-is-eating-the-world/">keep growing</a> for years to come.
If you’re like me and come from a small town in the countryside you may have already come to peace with the fact that if you want such a job you’ll have to say goodbye to your nice little village and relocate.</p>
<p>Software companies tend to build a handful of very big offices either in big cities (e.g. New York, Seattle) or in specific geographical areas (e.g. Silicon Valley), why? Perhaps for efficiency reasons: it lends to economies of scale to provide services for a greater number of employees out of a single location rather than having to provide the same services spread out over many smaller locations, and we all know that the biggest and most famous SW employers tend to offer a lot of perks among these services (did someone say food?).</p>
<p>So people are flocking to these well known locations in order to get a hold of a SW job and this doesn’t come without <a target="_blank" href="https://en.wikipedia.org/wiki/Gentrification">issues</a>.</p>
<p>Thankfully the world is not a place where things typically stand still so change is coming even in this particular field.
Thanks to both modern communication technologies and the increasing demand for software, job offers that don’t require the candidate to relocate are becoming a reality.</p>
<h2 id="what-is-remote-working">What is remote working?</h2>
<p>The term pretty much speaks for itself: These are jobs in which the employee can work from a location of his/her own choice without having to relocate to the company’s office location.</p>
<p><em>Oh cool, wait but what? Of course there are caveats, keep on reading.</em></p>
<h3 id="which-companies-tend-to-offer-remote-positions">Which companies tend to offer remote positions?</h3>
<p>Neither Google, Amazon nor {name your favorite big tech company} is going to hire you remotely, at least for the moment: these companies don’t generally offer remote jobs nowadays.
This doesn’t mean your hopes are lost, but only that you’ll have to set your aim somewhere else. There are plenty of smaller companies and startups that are driving the remote job market.
At least now you know where not to look.</p>
<h3 id="can-i-be-legally-employed">Can I be legally employed?</h3>
<p>This pretty much boils down to the countries the employee and employer are located in.</p>
<p><strong>Same country</strong>
If the employer has a legal entity in the same country you reside in then it is highly likely that you can be hired as a regular full time employee as per your country’s job laws: your rights and obligations will be similar to those of any other employee in that country.</p>
<p><strong>Different countries</strong>
If you don’t reside in the same country as your prospective employer it may be very difficult or not possible at all to get hired as an employee. These are some of the possible scenarios:</p>
<ul>
<li><p><em>Through an intermediary</em>
Some companies will hire you remotely across different countries with the help of a 3rd party. The 3rd party might often be a staffing or HR consulting firm which already has a legal entity in your country and with which you will sign the employment contract.
This will enable you to be legally employed with the only caveat that technically the actual employer will be the 3rd party company.</p>
</li>
<li><p><em>As a contractor</em>
This means you’ll set up your own legal entity to work as a self-employed person or freelance in your country and your prospective employer will hire you as a contractor.
This does not mean you will not feel like a regular employee, after all it is in the interest of your employer to make you feel part of the team, but it will certainly mean that:
1) You’ll get paid in a different way (i.e. sending out invoices instead of receiving a payslip).
2) You’ll have to take care of your own taxes and social security. This may be more or less of a burden depending on the tax laws of your country.
3) Any regulations which may be protecting employees in your country won’t apply to you because you’re technically not an employee.</p>
</li>
</ul>
<p><strong><em>This is a very important aspect: if you don’t feel comfortable working as a contractor and don’t live in the same country as your potential employer you might as well as give up looking for a remote job right now.</em></strong></p>
<h2 id="hunting-for-a-remote-job">Hunting for a remote job</h2>
<p><em>Set your expectations.</em></p>
<h3 id="dont-rush-it">Don’t rush it</h3>
<p>These things can take quite some time: allow at least 6 months to look for a remote job as the bare minimum, for many people this can easily go up to 1 or 2 years.</p>
<h3 id="internships-or-junior-roles">Internships or junior roles</h3>
<p>Remote working is still in its infancy so it is likely that your prospective employer won’t be yet set up to train junior employees or interns remotely. This means that most often remote positions will be reserved to candidates with medium to senior level experience. In other words: the employer will want to somehow ensure that the candidate can carry out the work as autonomously as possible and without relying on constant help: most often offering positions only for people with enough past experience is a way of achieving this.</p>
<h3 id="multiple-applications">Multiple applications</h3>
<p>Applying at Google or Amazon can be regarded as a “safe bet” in the sense that if any of those companies will hand you an offer at the end of the interview process you’ll most likely accept it without pondering too much over it.</p>
<p>Companies offering remote jobs often don’t have the same level of fame and notoriety of the ones above so chances are you won’t know much about the company you will be applying to. So please hedge your bets and apply to more than one company at the same time: it will speed up your job seeking process, let you gain more experience out of the additional chats and interviews and broaden your choices when it comes to picking which offer to accept. All of which will translate in increased chances of not having to regret your employer choice.</p>
<h3 id="where-to-apply-or-send-your-cv">Where to apply or send your CV?</h3>
<p><strong>Non-exhaustive list of websites (not in order of relevance)</strong></p>
<ul>
<li><p><a target="_blank" href="https://angel.co/">https://angel.co/</a></p>
</li>
<li><p><a target="_blank" href="https://www.idealist.org/">https://www.idealist.org/</a></p>
</li>
<li><p><a target="_blank" href="https://jsremotely.com/">https://jsremotely.com/</a></p>
</li>
<li><p><a target="_blank" href="https://javascript.works-hub.com/">https://javascript.works-hub.com/</a></p>
</li>
<li><p><a target="_blank" href="https://www.moonlightwork.com/">https://www.moonlightwork.com/</a></p>
</li>
<li><p><a target="_blank" href="https://powertofly.com/">https://powertofly.com/</a></p>
</li>
<li><p><a target="_blank" href="https://remote.co/">https://remote.co/</a></p>
</li>
<li><p><a target="_blank" href="https://remoteok.io/">https://remoteok.io/</a></p>
</li>
<li><p><a target="_blank" href="https://remotive.io/">https://remotive.io/</a></p>
</li>
<li><p><a target="_blank" href="https://remotelypeople.com/">https://remotelypeople.com/</a></p>
</li>
<li><p><a target="_blank" href="https://stackoverflow.com/jobs?r=true">https://stackoverflow.com/jobs?r=true</a></p>
</li>
<li><p><a target="_blank" href="https://www.themuse.com/">https://www.themuse.com/</a></p>
</li>
<li><p><a target="_blank" href="https://www.workingnomads.co/jobs">https://www.workingnomads.co/jobs</a></p>
</li>
<li><p><a target="_blank" href="https://weworkremotely.com/">https://weworkremotely.com/</a></p>
</li>
<li><p><a target="_blank" href="https://www.welcometothejungle.com/en/jobs">https://www.welcometothejungle.com/en/jobs</a></p>
</li>
</ul>
<p><strong>Useful posts</strong></p>
<ul>
<li><p><a target="_blank" href="https://www.glassdoor.com/blog/100-percent-remote-companies/">https://www.glassdoor.com/blog/100-percent-remote-companies/</a></p>
</li>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/reflections-on-being-a-remote-developer-757465ed1e9e/">https://www.freecodecamp.org/news/reflections-on-being-a-remote-developer-757465ed1e9e/</a></p>
</li>
</ul>
<p><strong>Non-exhaustive list of remote-friendly companies</strong></p>
<ul>
<li><a target="_blank" href="https://twitter.com/chris_herd/status/1202962206226292736?s=03">https://twitter.com/chris_herd/status/1202962206226292736?s=03</a></li>
</ul>
<p>Don’t forget you should also google for jobs yourself.</p>
<h2 id="learn-about-your-prospective-employer">Learn about your prospective employer</h2>
<p>Your prospective employer is trying to learn about you through its recruitment process: you should do the same (from a business, not a personal, perspective). You should try to assess the company you’re interviewing with to make sure the actual job and your expectation of it won’t be too far apart.</p>
<p>Your application and interview processes can vary greatly depending on the company you’re applying to. Here are some factors that can contribute to such differences when it comes to company size and experience:</p>
<h3 id="well-established-mediumbig-size-company"><strong>Well established, medium/big size company</strong></h3>
<p>Bigger companies usually have dedicated HR and recruiting staff which most likely will have already put in place well defined processes to handle remote job applications and their applicants.</p>
<p>Because of this, the employer will usually take a “leading” role in the application process, guiding you from the early phases of the application through the various interviews and eventually to an offer.</p>
<p>You’ll most likely have to go through one or more phone interviews or video calls and, if successful, will be “flown in” to the company’s office for some more interviews on-site.</p>
<h3 id="young-small-size-company-or-startup">Young, small size company or startup</h3>
<p>These companies usually don’t have full-time hiring staff, so don’t expect particularly structured hiring processes. Most likely you’ll get to speak with your prospective teammates and CEO since the early stages. The whole process may happen over video call and you may not get to physically meet your potential colleagues up until you’ve actually been hired.</p>
<h3 id="remote-first-or-remote-sometimes">Remote first or remote “sometimes”?</h3>
<p>Regardless of what a company may tell you about their culture being “remote first” this may not always hold true.</p>
<p>If the company culture does not really embrace remote working your dream job can quickly turn into a lonely nightmare.</p>
<p>A good “remote first” indicator is represented by the number of remote versus regular employees at the company (a very important question to ask during the hiring process).</p>
<p>Companies whose majority of employees are non-remote might unwittingly favor a non-remote friendly work style which might include:</p>
<ul>
<li><p>Having a lot of impromptu meetings in which remote employees are left out.</p>
</li>
<li><p>Sharing work related information during water cooler talk or during lunch time.</p>
</li>
<li><p>Being used to very quick interaction cycles which usually involve frequent “shoulder tapping” and interruptions.</p>
</li>
</ul>
<p>It’s hard to predict if this will be the case, but knowing beforehand that at least about half of the workforce is remote can make it a bit more likely that the company as a whole will think remote first.</p>
<h2 id="getting-through-the-interviews">Getting through the interviews</h2>
<p>It’s hard to predict what a job application will look like, but most often it is a multi step process which might involve phone calls, video conferences, assignments and sometimes in-person meetings.</p>
<p>Please note the phases described hereafter might not always be present in all application processes and/or might come in a different order.</p>
<h3 id="screening-phase">Screening phase</h3>
<p>This is the first contact from the prospective employer after you’ve sent them your CV or filled their online job application form.</p>
<p>It happens usually via email and its aim is to schedule an introductory phone or video call.</p>
<p>This very first call might not always be technical but it is usually meant as a form of assessment to make sure the applicant is legit. In other words, it is meant to quickly reject any persons who might have applied by mistake or that might be blatantly unfit for the job.</p>
<h3 id="remote-assignments">Remote assignments</h3>
<p>If the screening phase is successful you might get a request to complete an assignment which could be of various types: Either an online test or a timed coding challenge or just a request to develop a piece of code and deliver it after a few days.</p>
<h3 id="technical-interviews">Technical Interviews</h3>
<p>After your assignment is complete and has been positively reviewed you usually get a request for a technical interview. This means that you will talk most likely with people who are doing the same or a similar job to the one you are applying for. Expect a lot of technical questions here.</p>
<h3 id="hrmanagement-interview">HR/Management Interview</h3>
<p>This phase might happen at any time in the process, it will be the phase where you will meet non technical people from the company and during which you will talk about contracts, salary and perks.</p>
<h2 id="job-contract-bargaining">Job contract bargaining</h2>
<p>After passing all phases of the interviews if you’re successful you’ll be extended an offer which at a certain point will get written into a job contract.</p>
<p>What comes after mostly depends if you’re getting hired as an employee or as a contractor (please remember the “Can I be legally employed” section).</p>
<h3 id="as-an-employee">As an employee</h3>
<p>There’s usually not much room for bargaining besides the amount of pay (gross yearly amount) in this case.</p>
<p>You’ll most likely have to sign your country’s standard job contract and will get whatever social security benefits and whatever amount of vacation days the standard contract offers (which can differ greatly from country to country).</p>
<h3 id="as-a-contractor">As a contractor</h3>
<p>Things here get a bit more complicated: since there is no standard employment contract when working as a contractor, you’ll have to iron out all the things that are usually taken for granted when employed, these may comprise:</p>
<ul>
<li><p><strong>Salary amount</strong></p>
</li>
<li><p><strong>Salary currency</strong>
Your employer might be in a country with a different currency than yours in this case you should carefully negotiate who should carry the burden of the exchange rate.</p>
</li>
<li><p><strong>Vacation days</strong>
All countries have different laws and in some vacation days are included in an employment contract, in others they are not. You should not take for granted that your contract will or will not include vacation days. You should negotiate whatever suits you best.</p>
</li>
<li><p><strong>Sick days</strong>
There is no social security coverage for contractors when sick. Most employers won’t usually bother if you need to take a few days off because you’re sick. Of course you shouldn’t cheat or you’ll break the trust in the employee/employer relationship.</p>
</li>
<li><p><strong>Bank holidays
</strong>These are also up for negotiation. Some companies grant the bank holidays of the employee’s country, some prefer to have all employees adhering to the headquarter’s country bank holidays. Some won’t even grant bank holidays to contractors: YMMV.</p>
</li>
<li><p><strong>Leaving notice
</strong>This is your safeguard in case something goes awry. Leaving notice is the advance notice if one of the parties chooses to end the contract, this depends on how long on average it might take for you to find another job.</p>
</li>
<li><p><strong>Work hardware
</strong>In most cases the employer will provide the necessary hardware (i.e. a laptop), but if you already have the right gear you might “trade” the cost of the hardware for some other benefit.</p>
</li>
<li><p><strong>Conferences
</strong>Many companies have a budget for conferences, it might be wise to check if it also applies to remote employees.</p>
</li>
<li><p><strong>Business trips
</strong>Sooner or later you’ll have to travel to the company’s headquarters or to some company meeting. Making sure beforehand that such trips will be paid for by the company can avoid bad surprises when the need to travel arises.</p>
</li>
<li><p><strong>Other perks
</strong>There can be conutless other benefits that your prospective employer might be willing to offer you (or might not :) ). As with everything we’ve discussed so far these are all part of the bargaining process: it’s up to you if you want to ask your employer to pay for a certain benefit or if you prefer to factor this cost in the main salary upfront.</p>
</li>
</ul>
<h2 id="about-the-author">About the author</h2>
<p>My adventure with remote working started around 2 years ago.
I live in the countryside of Italy and used to work in the city of Milan: a journey which took away almost 2 hours of my life every morning and another 2 hours every evening.</p>
<p>My previous employers used to allow work from home once in a while, but no more than a day every week.</p>
<p>I tend to be very prone to distractions so my performance suffers in an office environment, especially one in which continous interruptions by collegaues are more likely to be the norm rather than the exception.</p>
<p>Pretty soon the single day I could spend working at home started becoming the dream of what I wanted my work life to be.</p>
<p>Being able to start coding in the morning and continue all the way through the afternoon was something very rarely I managed to experience when at the office.</p>
<p>So when the long commute to work started to feel unbearable I went looking for alternatives.</p>
<h3 id="the-search">The search</h3>
<p>At the time the vast majority of job offers I could find didn’t allow remote work and were either still based in Milan or required relocation.</p>
<p>Since relocation wasn’t an option due to family matters, I couldn’t stand the idea of having to stick to that long commute so one day while on Stack Overflow I noticed something uncommon in the usual job postings that appear in the right column: one of them was bearing a “REMOTE” badge… Boom! That was the spark that started everything. I simply had to factor in the “remote” keyword while looking for job posts and all of a sudden different kinds of job offers started surfacing from my searches.</p>
<p>Things didn’t go as quick as I hoped though: I had to exclude almost all of the offers from American companies because they required living in an American timezone. Remote work in Europe wasn’t that popular by then so it took several months before I could find some applicable open positions, apply to them and go through any interviews.</p>
<p>The effort has been rewarded though, I eventually found a company which looked like a very good match for my skills, goals and work culture and which has now become my current employer.</p>
<h3 id="the-good">The good</h3>
<p>So far it’s been almost 2 years since I’ve been working fully remotely and I’m very happy with the choice; the tools we use for remote work make the experience almost seamless and, apart from team building and other social moments, there hasn’t been a single time in which I felt the need of having to physically be at the company headquarters.</p>
<p>Even though I sometimes miss the social environment of the office, being able to reclaim 4 hours of commuting time every day has been priceless for me: I now have time to meet with friends and to stay with my loved ones and overall my life is better balanced now than it was before.</p>
<h3 id="the-not-so-good">The not so good</h3>
<p>So far the biggest downsides I could notice mainly boil down to 2 areas:</p>
<ul>
<li><p><strong>Fitness</strong>
Not all the people feel the need to excercise, I’m one of those. Remote working ended up making me enjoy sedentary life a bit too much so I eventually had to acknowledge that my body was suffering from a lack of fitness and had to start going to the gym.</p>
</li>
<li><p><strong>Serendipitous interaction</strong>
Believe it or not but living in a small town where the chance of randomly bumping into another software engineer is close to zero might make you feel “professionally lonely” at times.
Unfortunately I didn’t find a definitive solution to this yet, but I’ll try to keep you posted when I will!</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[RxJava error handling: OnErrorNotImplementedException vs UndeliverableException]]></title><description><![CDATA[I recently spent some time digging into RxJava’s error handling facilities and realized that throwables forwarded to RxJavaPlugins.setErrorHandler() are sometimes wrapped in OnErrorNotImplementedException and sometimes in UndeliverableException . I c...]]></description><link>https://blog.marcoromano.net/rxjava-error-handling-onerrornotimplementedexception-vs-undeliverableexception</link><guid isPermaLink="true">https://blog.marcoromano.net/rxjava-error-handling-onerrornotimplementedexception-vs-undeliverableexception</guid><dc:creator><![CDATA[Marco Romano]]></dc:creator><pubDate>Thu, 01 Nov 2018 17:29:39 GMT</pubDate><content:encoded><![CDATA[<p>I recently spent some time digging into RxJava’s error handling facilities and realized that throwables forwarded to RxJavaPlugins.setErrorHandler() are sometimes wrapped in OnErrorNotImplementedException and sometimes in UndeliverableException . I couldn’t easily figure out why and when so I drafted a piece of code that I hope might help others shed some light on the matter.</p>
<p>Exceptions can occur in many places in an RxJava chain but for this specific article we will cover three particular situations:</p>
<h2 id="1-upstream-exceptions">1) Upstream exceptions</h2>
<p>Exceptions coming from upstream (i.e. from the source we are hooking up to) are forwarded to the subscriber’s <code>onError()</code> if present, or wrapped in <code>OnErrorNotImplementedException</code> and sent to <code>RxJavaPlugins.setErrorHandler()</code> if not present.</p>
<h2 id="2-midstream-exceptions">2) Midstream exceptions</h2>
<p><em>I’m using the term ‘midstream’ here (which does not belong to RxJava’s vocabulary) solely for lack of a better term.</em></p>
<p>Exceptions thrown inside a subscriber’s <code>onNext()</code> are forwarded to their relative <code>onError()</code> if present, or wrapped in <code>OnErrorNotImplementedException</code> and sent to <code>RxJavaPlugins.setErrorHandler()</code> if not present.</p>
<h2 id="3-downstream-exceptions">3) Downstream exceptions</h2>
<p>Exceptions thrown inside a subscriber’s <code>onComplete()</code> or <code>onSuccess()</code> are not forwarded to their relative <code>onError()</code> even if present, they are instead wrapped in <code>UndeliverableException</code> and sent to <code>RxJavaPlugins.setErrorHandler()</code> .
Exceptions thrown inside <code>onError()</code> follow the same path.</p>
<h2 id="why-is-3-special">Why is 3) special?</h2>
<p>While 1) and 2) seem to be pretty straightforward why is 3) different? As mentioned in this <a target="_blank" href="https://github.com/ReactiveX/RxJava/issues/5099">enlightening RxJava issue</a>, these exceptions cannot be forwarded to <code>onError()</code> because <code>onError()</code> <code>onComplete()</code> and <code>onSuccess()</code> are terminal events of a flow and thereby must always be a flow’s last emission. Since the exception itself originated during a terminal event, forwarding it to <code>onError()</code> would imply emitting an <code>onError</code> event right after an <code>onSuccess</code> event thereby violating the definition of terminal event (for further info check out <a target="_blank" href="http://reactivex.io/documentation/contract.html">Rx’s Observable Contract</a>).</p>
<h2 id="caveat-emptor">Caveat emptor!</h2>
<p>This can get especially tricky when mixing Observables/Flowables and Singles/Maybes/Completables because the formers do emit <code>onNext</code> events, while the latters do not.</p>
<p>Let’s say you were processing an Observable’s events inside an <code>onNext</code> and handling relative errors in an <code>onError</code> : during a refactoring that Observable is changed into a Single, and so you “move” the event processing logic from <code>onNext</code> to <code>onSuccess</code> while keeping <code>onError</code> as is. This triggers a problem: If the event processing logic throws an Exception, it won’t be forwarded to<code>onError</code> anymore but is instead wrapped in <code>UndeliverableException</code> and sent to <code>RxJavaPlugins.setErrorHandler()</code> .</p>
<h2 id="too-much-talking-show-me-the-code">Too much talking, show me the code!</h2>
<p>Here you go and thanks for reading!</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">package</span> net.kjulio.rx.test

<span class="hljs-keyword">import</span> io.reactivex.Completable
<span class="hljs-keyword">import</span> io.reactivex.Flowable
<span class="hljs-keyword">import</span> io.reactivex.Maybe
<span class="hljs-keyword">import</span> io.reactivex.Observable
<span class="hljs-keyword">import</span> io.reactivex.Single
<span class="hljs-keyword">import</span> io.reactivex.exceptions.OnErrorNotImplementedException
<span class="hljs-keyword">import</span> io.reactivex.exceptions.UndeliverableException
<span class="hljs-keyword">import</span> io.reactivex.functions.Consumer
<span class="hljs-keyword">import</span> io.reactivex.plugins.RxJavaPlugins
<span class="hljs-keyword">import</span> org.junit.Assert
<span class="hljs-keyword">import</span> org.junit.Test

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RxErrorDeliveryTest</span> </span>{

    <span class="hljs-meta">@Test</span>
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">upstreamErrorsAreRoutedToGlobalHandlerWhenOnErrorIsMissing</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">val</span> list = mutableListOf&lt;Throwable&gt;()
        RxJavaPlugins.setErrorHandler { list.add(it) }

        Flowable.error&lt;Any&gt;(RuntimeException()).subscribe()
        Observable.error&lt;Any&gt;(RuntimeException()).subscribe()
        Single.error&lt;Any&gt;(RuntimeException()).subscribe()
        Maybe.error&lt;Any&gt;(RuntimeException()).subscribe()
        Completable.error(RuntimeException()).subscribe()

        Assert.assertEquals(<span class="hljs-number">5</span>, list.size)
        list.forEach {
            Assert.assertTrue(it <span class="hljs-keyword">is</span> OnErrorNotImplementedException)
            Assert.assertTrue(it.cause <span class="hljs-keyword">is</span> RuntimeException)
        }
    }

    <span class="hljs-meta">@Test</span>
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">upstreamErrorsAreNotRoutedToGlobalHandlerWhenOnErrorIsPresent</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">val</span> list = mutableListOf&lt;Throwable&gt;()
        RxJavaPlugins.setErrorHandler { list.add(it) }

        Flowable.error&lt;Any&gt;(RuntimeException()).subscribe({}, {})
        Observable.error&lt;Any&gt;(RuntimeException()).subscribe({}, {})
        Single.error&lt;Any&gt;(RuntimeException()).subscribe({}, {})
        Maybe.error&lt;Any&gt;(RuntimeException()).subscribe({}, {})
        Completable.error(RuntimeException()).subscribe({}, {})

        Assert.assertEquals(<span class="hljs-number">0</span>, list.size)
    }

    <span class="hljs-meta">@Test</span>
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">downstreamErrorsAreAlwaysRoutedToGlobalHandlerRegardlessOfOnErrorPresence</span><span class="hljs-params">()</span></span> {
        <span class="hljs-comment">// They couldn't be routed to onError (when present) because the stream has already</span>
        <span class="hljs-comment">// completed and by contract invoking onError would represent another emission.</span>

        <span class="hljs-keyword">val</span> list = mutableListOf&lt;Throwable&gt;()
        RxJavaPlugins.setErrorHandler { list.add(it) }

        Single.just(<span class="hljs-string">""</span>).subscribe(Consumer { <span class="hljs-keyword">throw</span> RuntimeException() })
        Maybe.just(<span class="hljs-string">""</span>).subscribe { <span class="hljs-keyword">throw</span> RuntimeException() }
        Completable.complete().subscribe { <span class="hljs-keyword">throw</span> RuntimeException() }

        Flowable.just(<span class="hljs-string">""</span>).subscribe({}, {}, { <span class="hljs-keyword">throw</span> RuntimeException() })
        Observable.just(<span class="hljs-string">""</span>).subscribe({}, {}, { <span class="hljs-keyword">throw</span> RuntimeException() })
        Single.just(<span class="hljs-string">""</span>).subscribe({ <span class="hljs-keyword">throw</span> RuntimeException() }, {})
        Maybe.just(<span class="hljs-string">""</span>).subscribe({ <span class="hljs-keyword">throw</span> RuntimeException() }, {})
        Completable.complete().subscribe({ <span class="hljs-keyword">throw</span> RuntimeException() }, {})

        Assert.assertEquals(<span class="hljs-number">8</span>, list.size)
        list.forEach {
            Assert.assertTrue(it <span class="hljs-keyword">is</span> UndeliverableException)
            Assert.assertTrue(it.cause <span class="hljs-keyword">is</span> RuntimeException)
        }
    }

    <span class="hljs-meta">@Test</span>
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">midstreamErrorsAreRoutedToGlobalHandlerWhenOnErrorIsMissing</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">val</span> list = mutableListOf&lt;Throwable&gt;()
        RxJavaPlugins.setErrorHandler { list.add(it) }

        Flowable.just(<span class="hljs-string">""</span>).subscribe { <span class="hljs-keyword">throw</span> RuntimeException() }
        Observable.just(<span class="hljs-string">""</span>).subscribe { <span class="hljs-keyword">throw</span> RuntimeException() }

        Assert.assertEquals(<span class="hljs-number">2</span>, list.size)
        list.forEach {
            Assert.assertTrue(it <span class="hljs-keyword">is</span> OnErrorNotImplementedException)
            Assert.assertTrue(it.cause <span class="hljs-keyword">is</span> RuntimeException)
        }
    }

    <span class="hljs-meta">@Test</span>
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">midstreamErrorsAreNotRoutedToGlobalHandlerWhenOnErrorIsPresent</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">val</span> list = mutableListOf&lt;Throwable&gt;()
        RxJavaPlugins.setErrorHandler { list.add(it) }

        Flowable.just(<span class="hljs-string">""</span>).subscribe({ <span class="hljs-keyword">throw</span> RuntimeException() }, {})
        Observable.just(<span class="hljs-string">""</span>).subscribe({ <span class="hljs-keyword">throw</span> RuntimeException() }, {})

        Assert.assertEquals(<span class="hljs-number">0</span>, list.size)
    }
}
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Writing TypeScript on a laptop? This might improve your battery life.]]></title><description><![CDATA[Two things happened recently:

My laptop’s battery was draining out too fast.

I began learning TypeScript.


I’m using tsc (TypeScript’s compiler) in watch mode which is very convenient to trigger automatic transpilation while developing.
But here’s...]]></description><link>https://blog.marcoromano.net/writing-typescript-on-a-laptop-this-might-improve-your-battery-life</link><guid isPermaLink="true">https://blog.marcoromano.net/writing-typescript-on-a-laptop-this-might-improve-your-battery-life</guid><dc:creator><![CDATA[Marco Romano]]></dc:creator><pubDate>Wed, 04 Jan 2017 21:03:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1632308572072/-1feNjpRV.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Two things happened recently:</p>
<ul>
<li><p>My laptop’s battery was draining out too fast.</p>
</li>
<li><p>I began learning <a target="_blank" href="https://www.typescriptlang.org/">TypeScript</a>.</p>
</li>
</ul>
<p>I’m using <code>tsc</code> (TypeScript’s compiler) in <a target="_blank" href="https://www.typescriptlang.org/docs/handbook/compiler-options.html">watch mode</a> which is very convenient to trigger automatic transpilation while developing.</p>
<p>But here’s what happens:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1632308566078/aKmfihhpc.png" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1632308567579/CmcrifIFn.png" alt /></p>
<p>Node (which the TypeScript compiler runs on) is eating 8% of CPU cycles just while sitting down waiting for file changes. WOW.</p>
<p>A quick digging around pointed me to this link: <a target="_blank" href="https://github.com/Microsoft/TypeScript/pull/8196/">https://github.com/Microsoft/TypeScript/pull/8196/</a></p>
<p>Apparently <code>tsc</code> reverted to a polling approach to watch for file changes which appears to be quite resource intensive. They made this choice because the non-polling approach used previously turned out to be slow at detecting file changes in many cases.</p>
<h3 id="but-not-all-hope-is-lost">But not all hope is lost!</h3>
<p>Luckily the non-polling file watcher is still in the code and can be enabled by setting this environment variable: <code>TSC_NONPOLLING_WATCHER="1"</code> .</p>
<p>So now watch this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1632308569256/GYQ0aa1JP.png" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1632308570606/uH3yn9QUh.png" alt /></p>
<p>Now it is like it should be: No file changes, no CPU usage.</p>
<p>Up until now I did not notice any laziness at detecting file changes on a 2016 MacBook Pro 13" running mac OS 10.12.2 and the battery life got a big improvement since then.</p>
<p>Hope this helps.</p>
<p>Marco</p>
]]></content:encoded></item><item><title><![CDATA[Working around an infamous macOS Sierra Dock bug]]></title><description><![CDATA[Lately I’m running more and more into an infamous macOS bug whereas the Dock.app somehow hangs leaving the macOS GUI in a semi-stuck state in which, depending on the odds, you might find yourself unable to:

Launch Mission Control (either via keyboar...]]></description><link>https://blog.marcoromano.net/working-around-an-infamous-macos-sierra-dock-bug</link><guid isPermaLink="true">https://blog.marcoromano.net/working-around-an-infamous-macos-sierra-dock-bug</guid><dc:creator><![CDATA[Marco Romano]]></dc:creator><pubDate>Sun, 01 Jan 2017 17:08:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1632308559446/zLf8bv28v.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Lately I’m running more and more into an infamous macOS bug whereas the Dock.app somehow hangs leaving the macOS GUI in a semi-stuck state in which, depending on the odds, you might find yourself unable to:</p>
<ul>
<li><p>Launch Mission Control (either via keyboard or hot corner).</p>
</li>
<li><p>Launch any app from the dock (sometimes clicking and holding on a dock icon does bring up the contextual menu though the menu itself doesn’t react to any clicks whatsoever).</p>
</li>
<li><p>Launch Spotlight (either via keyboard shortcut or by clicking its icon in the menu bar).</p>
</li>
<li><p>Force quit any app (pressing CMD-ALT-ESC will bring up the force quit window though it doesn’t react to any clicks whatsoever).</p>
</li>
<li><p>Something else: YMMV.</p>
</li>
</ul>
<p>The only symptom that happens 100% of the times is the inability to launch Mission Control, the others happen randomly.</p>
<h2 id="when-does-this-happen">When does this happen?</h2>
<p>Though I can’t seem to reliably reproduce the bug, it usually happens right after dragging a recently downloaded file from the Downloads stack in the dock to the desktop.</p>
<h2 id="trivial-workaround">Trivial workaround</h2>
<p>If the dock icons are still clickable and/or Spotlight can still be launched the workaround is trivial:</p>
<p><strong>Launch the Terminal app from either Spotlight or from a Dock shortcut (if you have one) and run the <code>killall Dock</code> command.</strong></p>
<h2 id="a-little-less-than-trivial-workaround">A little less than trivial workaround</h2>
<p>If the GUI is stuck so much you can’t launch the Terminal app in any way or you can’t type any command in it because the keyboard input is stuck too then your only chance is to force shutdown your Mac and start over.</p>
<h3 id="but">But…</h3>
<p>You can be proactive and prepare a better workaround that should work most of the times:</p>
<ul>
<li>Open the Script Editor application and create a new AppleScript with the following line inside: <code>do shell script "killall Dock"</code></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1632308556184/7GDFfKzc4.png" alt /></p>
<ul>
<li>Save it in the <em>Applications</em> folder with file format <em>Application</em> and file name <em>Kill Dock.app</em></li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1632308557696/7CuHDkD-b.png" alt /></p>
<ul>
<li>Use Siri to launch this newly created AppleScript Application whenever your Dock gets stuck.
As strange as it may seem, Siri stays fully operational after the Dock hangs, so just hit the Siri key on the keyboard (or Touch Bar) and tell Siri: “open Kill Dock”.</li>
</ul>
<p>Voila: Siri will launch the AppleScript command and reset your dock for you.</p>
<p>Hope this helps.</p>
<h2 id="update-20170224">Update 2017–02–24:</h2>
<p>It seems that the macOS Sierra 10.12.3 update fixed this bug. A workaround is no longer needed therefore.</p>
]]></content:encoded></item></channel></rss>