Shared posts

09 Dec 15:46

Advanced Placement Data – CSA and CSP for 2019

by barbarerumichedu

The Advanced Placement (AP) data is out for 2019 at the College Board at https://research.collegeboard.org/programs/ap/data/participation/ap-2019

I have downloaded the data and written Python programs to process it along with data from prior years. See the following spreadsheets for more information.

The number of AP CSA exams taken in the U.S. increased from 60,040 in 2018 to 64,197 in 2019 (a 7% increase). The number of AP CSP exams taken in the U.S. increased from 70,864 in 2018 to 94,360 in 2019 (a 33% increase).

The percentage of females taking the AP CSA exam increased from 24% in 2018 to 24.5% in 2019. However, this is still the second worse percentage of females in AP after Physics C:elec. & magnet which is 24.3%. The percentage of females taking the AP CSP exam increased from 31.5% in 2018 to 32.7% in 2019. This is still the 5th worst percentage of females. Most (26 of 38 – 68%) of the AP exams have a higher percentage of females than males taking the exam.

The average pass rate on CSA for 2019 was 69.2% and for CSP it was 71.7%. These pass rates are better than Calculus AB which was 57.8%. However, the pass rate for Black students on CSA was 37.1% and CSP was 41.9%. The Hispanic pass rate was 46.9% for CSA and 54.4% for CSP. The Female pass rate for CSA was 66.8% and for CSP was 69.4%.

The top 10 states with the highest number of exams per 100,000 of population are:

  1. New Jersey at 47.5
  2. Virginia at 42.2
  3. Massachusetts at 39.2
  4. Connecticut at 33.9
  5. Maryland at 33.5
  6. California at 32.7
  7. Washington at 30.6
  8. Illinois at 28.1
  9. Delaware at 26.1
  10. Texas at 25.1

12 Nov 00:16

Cleaning the Table

by Kieran Healy

While I’m talking about getting data into R this weekend, here’s another quick example that came up in class this week. The mortality data in the previous example were nice and clean coming in the door. That’s usually not the case. Data can be and usually is messy in all kinds of ways. One of the most common, particularly in the case of summary tables obtained from some source or other, is that the values aren’t directly usable. The following summary table was copied and pasted into Excel from an external source, saved as a CSV file, and arrived looking like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

library(tidyverse)

rfm_tbl <- read_csv("data/rfm_table.csv")


## Parsed with column specification:
## cols(
##   SEGMENT = col_character(),
##   DESCRIPTION = col_character(),
##   R = col_character(),
##   F = col_character(),
##   M = col_character()
## )


rfm_tbl 


## # A tibble: 23 x 5
##    SEGMENT        DESCRIPTION                             R     F     M    
##    <chr>          <chr>                                   <chr> <chr> <chr>
##  1 <NA>           <NA>                                    <NA>  <NA>  <NA> 
##  2 Champions      Bought recently, buy often and spend t… 4– 5  4– 5  4– 5 
##  3 <NA>           <NA>                                    <NA>  <NA>  <NA> 
##  4 Loyal Custome… Spend good money. Responsive to promot… 2– 5  3– 5  3– 5 
##  5 <NA>           <NA>                                    <NA>  <NA>  <NA> 
##  6 Potential Loy… Recent customers, spent good amount, b… 3– 5  1– 3  1– 3 
##  7 <NA>           <NA>                                    <NA>  <NA>  <NA> 
##  8 New Customers  Bought more recently, but not often     4– 5  <= 1  <= 1 
##  9 <NA>           <NA>                                    <NA>  <NA>  <NA> 
## 10 Promising      Recent shoppers, but haven’t spent much 3– 4  <= 1  <= 1 
## # … with 13 more rows

This is messy and we can’t do anything with the values in R, F, and M. Ultimately we want a table with separate columns containing the low and high values for these variables. If no lower bound is shown, the lower bound is zero. We’re going to use a few tools, notably separate() to get where we want to be. I’ll step through this pipeline one piece at a time, so you can see how the table is being changed from start to finish.

First let’s clean clean the variable names and remove the entirely blank lines.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20

rfm_tbl %>% 
  janitor::clean_names() %>%
  filter_all(any_vars(!is.na(.))) 


## # A tibble: 11 x 5
##    segment        description                             r     f     m    
##    <chr>          <chr>                                   <chr> <chr> <chr>
##  1 Champions      Bought recently, buy often and spend t… 4– 5  4– 5  4– 5 
##  2 Loyal Custome… Spend good money. Responsive to promot… 2– 5  3– 5  3– 5 
##  3 Potential Loy… Recent customers, spent good amount, b… 3– 5  1– 3  1– 3 
##  4 New Customers  Bought more recently, but not often     4– 5  <= 1  <= 1 
##  5 Promising      Recent shoppers, but haven’t spent much 3– 4  <= 1  <= 1 
##  6 Need Attention Above average recency, frequency & mon… 2– 3  2– 3  2– 3 
##  7 About To Sleep Below average recency, frequency & mon… 2– 3  <= 2  <= 2 
##  8 At Risk        Spent big money, purchased often but l… <= 2  2– 5  2– 5 
##  9 Can’t Lose Th… Made big purchases and often, but long… <= 1  4– 5  4– 5 
## 10 Hibernating    Low spenders, low frequency, purchased… 1– 2  1– 2  1– 2 
## 11 Lost           Lowest recency, frequency & monetary s… <= 2  <= 2  <= 2

Next we start work on the values. I thought about different ways of doing this, notably working out a way to apply or map separate() to each of the columns I want to change. I got slightly bogged down doing this, and instead decided to lengthen the r, f, and m variables into a single key-value pair, do the recoding there, and then widen the result again. First, lengthen the data:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21

rfm_tbl %>% 
  janitor::clean_names() %>%
  filter_all(any_vars(!is.na(.))) %>%
  pivot_longer(cols = r:m)


## # A tibble: 33 x 4
##    segment         description                                  name  value
##    <chr>           <chr>                                        <chr> <chr>
##  1 Champions       Bought recently, buy often and spend the mo… r     4– 5 
##  2 Champions       Bought recently, buy often and spend the mo… f     4– 5 
##  3 Champions       Bought recently, buy often and spend the mo… m     4– 5 
##  4 Loyal Customers Spend good money. Responsive to promotions   r     2– 5 
##  5 Loyal Customers Spend good money. Responsive to promotions   f     3– 5 
##  6 Loyal Customers Spend good money. Responsive to promotions   m     3– 5 
##  7 Potential Loya… Recent customers, spent good amount, bought… r     3– 5 
##  8 Potential Loya… Recent customers, spent good amount, bought… f     1– 3 
##  9 Potential Loya… Recent customers, spent good amount, bought… m     1– 3 
## 10 New Customers   Bought more recently, but not often          r     4– 5 
## # … with 23 more rows

I’m quite sure that there’s an elegant way to use one of the map() functions to process the r, f, and m columns in sequence. But seeing as I couldn’t quickly figure it out, this alternative strategy works just fine. In fact, as a general approach I think it’s always worth remembering that the tidyverse really “wants” your data to be in long form, and lots of things that are awkward or conceptually tricky can suddenly become much easier if you get the data into the shape that the function toolbox wants it to be in. Lengthening the data you’re working with is very often the right approach, and you know you can widen it later on once you’re done cleaning or otherwise manipulating it.

With our table in long format we can now use separate() on the value column. The separate() function is very handy for pulling apart variables that should be in different columns. Its defaults are good, too. In this case I didn’t have to write a regular expression to specify the characters that are dividing up the values. In the function call we use convert = TRUE to turn the results into integers, and fill = "left" because there’s an implicit zero on the left of each entry that looks like e.g. <= 2.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

rfm_tbl %>% 
  janitor::clean_names() %>%
  filter_all(any_vars(!is.na(.))) %>%
  pivot_longer(cols = r:m) %>% 
  separate(col = value, into = c("lo", "hi"), 
           remove = FALSE, convert = TRUE, 
           fill = "left") 


## # A tibble: 33 x 6
##    segment       description                        name  value    lo    hi
##    <chr>         <chr>                              <chr> <chr> <int> <int>
##  1 Champions     Bought recently, buy often and sp… r     4– 5      4     5
##  2 Champions     Bought recently, buy often and sp… f     4– 5      4     5
##  3 Champions     Bought recently, buy often and sp… m     4– 5      4     5
##  4 Loyal Custom… Spend good money. Responsive to p… r     2– 5      2     5
##  5 Loyal Custom… Spend good money. Responsive to p… f     3– 5      3     5
##  6 Loyal Custom… Spend good money. Responsive to p… m     3– 5      3     5
##  7 Potential Lo… Recent customers, spent good amou… r     3– 5      3     5
##  8 Potential Lo… Recent customers, spent good amou… f     1– 3      1     3
##  9 Potential Lo… Recent customers, spent good amou… m     1– 3      1     3
## 10 New Customers Bought more recently, but not oft… r     4– 5      4     5
## # … with 23 more rows

Before widening the data again we drop the value column. We don’t need it anymore. (It will mess up the widening if we keep it, too: try it and see what happens.)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

rfm_tbl %>% 
  janitor::clean_names() %>%
  filter_all(any_vars(!is.na(.))) %>%
  pivot_longer(cols = r:m) %>% 
  separate(col = value, into = c("lo", "hi"), 
           remove = FALSE, convert = TRUE, 
           fill = "left") %>%
  select(-value) 


## # A tibble: 33 x 5
##    segment        description                             name     lo    hi
##    <chr>          <chr>                                   <chr> <int> <int>
##  1 Champions      Bought recently, buy often and spend t… r         4     5
##  2 Champions      Bought recently, buy often and spend t… f         4     5
##  3 Champions      Bought recently, buy often and spend t… m         4     5
##  4 Loyal Custome… Spend good money. Responsive to promot… r         2     5
##  5 Loyal Custome… Spend good money. Responsive to promot… f         3     5
##  6 Loyal Custome… Spend good money. Responsive to promot… m         3     5
##  7 Potential Loy… Recent customers, spent good amount, b… r         3     5
##  8 Potential Loy… Recent customers, spent good amount, b… f         1     3
##  9 Potential Loy… Recent customers, spent good amount, b… m         1     3
## 10 New Customers  Bought more recently, but not often     r         4     5
## # … with 23 more rows

Now we can widen the data, with pivot_wider().

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

rfm_tbl %>% 
  janitor::clean_names() %>%
  filter_all(any_vars(!is.na(.))) %>%
  pivot_longer(cols = r:m) %>% 
  separate(col = value, into = c("lo", "hi"), 
           remove = FALSE, convert = TRUE, 
           fill = "left") %>%
  select(-value) %>%
  pivot_wider(names_from = name, 
              values_from = lo:hi) 


## # A tibble: 11 x 8
##    segment     description               lo_r  lo_f  lo_m  hi_r  hi_f  hi_m
##    <chr>       <chr>                    <int> <int> <int> <int> <int> <int>
##  1 Champions   Bought recently, buy of…     4     4     4     5     5     5
##  2 Loyal Cust… Spend good money. Respo…     2     3     3     5     5     5
##  3 Potential … Recent customers, spent…     3     1     1     5     3     3
##  4 New Custom… Bought more recently, b…     4    NA    NA     5     1     1
##  5 Promising   Recent shoppers, but ha…     3    NA    NA     4     1     1
##  6 Need Atten… Above average recency, …     2     2     2     3     3     3
##  7 About To S… Below average recency, …     2    NA    NA     3     2     2
##  8 At Risk     Spent big money, purcha…    NA     2     2     2     5     5
##  9 Can’t Lose… Made big purchases and …    NA     4     4     1     5     5
## 10 Hibernating Low spenders, low frequ…     1     1     1     2     2     2
## 11 Lost        Lowest recency, frequen…    NA    NA    NA     2     2     2

Finally we put back those implicit zeros using replace_na() and reorder the columns to our liking. Using replace_na() is fine here because we know that every missing value should in fact be a zero.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

rfm_tbl %>% 
  janitor::clean_names() %>%
  filter_all(any_vars(!is.na(.))) %>%
  pivot_longer(cols = r:m) %>% 
  separate(col = value, into = c("lo", "hi"), 
           remove = FALSE, convert = TRUE, 
           fill = "left") %>%
  select(-value) %>%
  pivot_wider(names_from = name, 
              values_from = lo:hi) %>%
  mutate_if(is.integer, replace_na, 0) %>%
  select(segment, 
         lo_r, hi_r, 
         lo_f, hi_f, 
         lo_m, hi_m, 
         description)


## # A tibble: 11 x 8
##    segment      lo_r  hi_r  lo_f  hi_f  lo_m  hi_m description             
##    <chr>       <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>                   
##  1 Champions       4     5     4     5     4     5 Bought recently, buy of…
##  2 Loyal Cust…     2     5     3     5     3     5 Spend good money. Respo…
##  3 Potential …     3     5     1     3     1     3 Recent customers, spent…
##  4 New Custom…     4     5     0     1     0     1 Bought more recently, b…
##  5 Promising       3     4     0     1     0     1 Recent shoppers, but ha…
##  6 Need Atten…     2     3     2     3     2     3 Above average recency, …
##  7 About To S…     2     3     0     2     0     2 Below average recency, …
##  8 At Risk         0     2     2     5     2     5 Spent big money, purcha…
##  9 Can’t Lose…     0     1     4     5     4     5 Made big purchases and …
## 10 Hibernating     1     2     1     2     1     2 Low spenders, low frequ…
## 11 Lost            0     2     0     2     0     2 Lowest recency, frequen…

Much nicer.

12 Nov 00:16

Twitter Favorites: [ReneeStephen] @sillygwailo Big Tree Energy Big Tree Data

Renée Stephen @ReneeStephen
@sillygwailo Big Tree Energy Big Tree Data
12 Nov 00:15

Above Avalon Podcast Episode 158: Forced to Sell

by Neil Cybart

How did Fitbit go from being considered the wearables leader to viewing a $2.1B acquisition as its best hope for shareholders to recoup any value? What led Fitbit to run out of options as an independent company? In episode 158, Neil discusses how Apple Watch forced Fitbit to sell itself. Additional topics include Google’s acquisition offer for Fitbit, how Apple Watch redefined the wrist wearables industry, and the most damning evidence of Fitbit’s demise.

To listen to episode 158, go here

The complete Above Avalon podcast episode archive is available here

12 Nov 00:15

Which side are you on, Britain? #GE2019 pic.twitter.com/L0uz0PxcyM

by ottocrat
mkalus shared this story from ottocrat on Twitter.

Which side are you on, Britain? #GE2019 pic.twitter.com/L0uz0PxcyM






78 likes, 43 retweets
12 Nov 00:15

DNA Lounge: Wherein Facebook continues the war against its own customers.

by jwz
mkalus shared this story from jwz.

We have a band coming up next Tuesday called Chastity, and....

You say rejected ad, I say emergent new flyer design.

Previously, previously.

12 Nov 00:12

North Shore Housing? Thanks Tsleil-Waututh and Squamish!

by Barry Rueger

If you’ve been following the plans by the Squamish nation to build 6000 units of housing near the Burrard Bridge, you’ll appreciate the sheer bravado of the local Tsleil-Waututh Nation.

Instead of waiting years for a District of North Vancouver council to finally approve a significant housing development, they’ve applied to the federal government to add the 45 hectares of the target property to their reserve lands. This would mean they could proceed without council approval.

Or, as one grouch on Twitter described it:

Last year Darwin Properties and the Tsleil-Waututh presented an ambitious new project called the Maplewood Innovation District, defined as “a new district offering an innovative mix of employment, education, recreational and limited residential and community uses in a campus-style structure.”

It would have built student and rental housing, commercial and studio space, and a variety of amenities on largely vacant land between the Mount Seymour Parkway and the Dollarton Highway. The proposal described plans for “a mix of housing tenures including 680 rental housing units (450 non-market and 230 market) and 220 market ownership units to co-locate jobs and residents and to support employment-generating uses.“


In July of 2018 the outgoing council chose to punt the proposal ’til after the election. The new council, who seem to be opposed to any development larger than coachhouses, quickly rejected it.

A second, much reduced version was also deferred in May of this year “until after the OCP review.” It seems likely though that opinions like those of council member Lisa Muri played a significant part in that decision. She was quoted in the North Shore News as saying:

“I didn’t use to converse with [Darwin] and now I do. Keep your enemies close, is what my initial thought was,” she said. Still, she said the project felt exclusionary for anyone who wasn’t a young tech employee on a bicycle.

“I felt like it was a party I wasn’t invited to,” she said.

The Tsleil-Waututh have now applied to the Government of Canada to annex the land and add it to their reserve holdings, which essentially moves it out of the reach of District council. (Aside from negotiations on shared infrastructure, like water and sewer.)

Last month, the adjacent Squamish nation announced their own plan to build 1,000 units of new housing, much of it geared to income, on the North Shore and in Squamish. The Hiy̓ám̓ ta Sḵwx̱wú7mesh Housing Society specifically wants to build housing for their own members but the development will still impact the rest of the North Shore housing market.

More than one pundit has suggested that the reason for the incredible traffic jams at both North Shore bridges is because so many people who work on the North Shore can’t afford to have a home here.

I guess it turns out that the biggest obstacle to settling on the North Shore was, in fact, Settler Culture.

12 Nov 00:12

Projected Members and Activity Levels

by Richard Millington

Too many communities are launched with features they will never be able to support.

The number of features your community deploys should be driven by two things.

The first, obviously, is your community strategy.

If you want the community to be resolving questions, suggesting ideas, sharing expertise in long-form, and connecting with each other then you need the Q&A, ideation, blog, and group features to enable that.

But this should be countered by your membership projections.

The fewer members you project, the less features you should deploy. There simply isn’t enough energy and attention to support them (regardless of how ambitious you want to be). Some features, notably groups, need a huge base of members to thrive.

This means you need to prioritise features and deploy just the ones you can support.

Given the median number of monthly active members in a customer community is somewhere around 550, this should temper your ambitions.

  • Below 200 active contributors: Q&A only.
  • 200 to 400 active contributors: Q&A + events/webinars
  • 400 to 700 active contributors: Q&A + events/webinars + ideas
  • 700 to 1,000 active contributors: Q&A + events/webinars + ideas + knowledge base
  • 1,000+ active contributors: Q&A + events/webinars + ideas + knowledge base + groups.

Treat these as general principles rather than rigid rules.

Bose, for example, has around 1,000 active participants but only uses Q&A.

Sophos has around 350 active participants and uses both groups and a knowledge base.

Two more important points here:

First, before you determine what features your community should have (or whether to deploy more) you need an accurate membership projection (use our template here).

Second, your community platform is never finished. It needs regular updates (some big, some minor) to ensure it has the right number of features for the number of active members.

12 Nov 00:12

Upgrading From Email To Fmail

by noreply@blogger.com (BOB HOFFMAN)

Email was fun, but we can do better.

It's time for us to disrupt the entire personal communication ecosystem. We need to upgrade to fmail.

Email was good for two types of things:
1. Receiving annoying messages from people we know who want something from us, and
2. Receiving annoying messages from people we don't know who want something from us.

The time has come for us to bifurcate. I love to say bifurcate.

Email can remain the system of choice to connect with the people we know. It would be made up primarily of messages concerning...

   - Meetings we don't want to go to
   - Dinners we don't want to eat
   - Parties we don't want to attend
   - Weddings taking place on days we were planning to play golf
   - People cancelling lunch plans
   - Naughty jokes that aren't funny
   - Political opinions that are hilariously funny

Then there's fmail.

First of all, let's not pretend we don't know what the f stands for. Fmail would constitute about 99% of what is currently called email. It would include...

   - Notifications that we have to update Flash
   - Invitations to attend the Double Secret Real-Time Programmatic Insider Summit
   - Amazing deals on airline flights to places we don't want to go
   - Amazing deals on hotel rooms we don't want to occupy
   - It's someone on LinkedIn's birthday!
   - How do rate our recent stay at St. Larry's Hospital?

There are other changes that need to be made to the messaging ecosystem. Just to get the ball rolling... If you're a male athlete, please don't text me pictures of your dick. Also, if you're a Russian female athlete, please don't text me pictures of your dick.

12 Nov 00:10

It seems sharing play-lists is no longer an inn...

by Ton Zijlstra

It seems sharing play-lists is no longer an innocent behaviour, nor is playing YouTube with the sound on in the presence of automated speech recognition like Google’s, Amazon’s and Apple’s cloud connected microphones in your living room. “CommanderSongs can be spread through Internet (e.g., YouTube) and radio.

The easiest mitigation of course is not having such microphones in your home in the first place. Another is running your own ASR with your 95% standard commands localized in the device. Edge first like Candle proposes, not cloud first.

Bookmarked CommanderSong: A Systematic Approach for Practical Adversarial Voice Recognition (arXiv.org)
The popularity of ASR (automatic speech recognition) systems, like Google Voice, Cortana, brings in security concerns, as demonstrated by recent attacks. The impacts of such threats, however, are less clear, since they are either less stealthy (producing noise-like voice commands) or requiring the physical presence of an attack device (using ultrasound). In this paper, we demonstrate that not only are more practical and surreptitious attacks feasible but they can even be automatically constructed. Specifically, we find that the voice commands can be stealthily embedded into songs, which, when played, can effectively control the target system through ASR without being noticed. For this purpose, we developed novel techniques that address a key technical challenge: integrating the commands into a song in a way that can be effectively recognized by ASR through the air, in the presence of background noise, while not being detected by a human listener. Our research shows that this can be done automatically against real world ASR applications. We also demonstrate that such CommanderSongs can be spread through Internet (e.g., YouTube) and radio, potentially affecting millions of ASR users. We further present a new mitigation technique that controls this threat.
12 Nov 00:09

Can you have a clean domain model?

by Eric Normand

I was asked a great question by a listener about whether it's always possible to find a good domain model. Sometimes, the business rules are so messy, how can we find something clean and stable? In this episode, I explore how we can find a stable and clean domain model within the chaos.

The post Can you have a clean domain model? appeared first on LispCast.

12 Nov 00:06

Ich mache jetzt noch etwas anderes

by Volker Weber

Bei mir beginnt alles mit Menschen. Vor 28 Jahren war es Raymond Wisemann, der zu mir sagte: "Schreib das mal selbst auf." Und nicht viel später Ingo T. Storm, der mir anbot, doch was für die c't zu schreiben. Ohne die positive Erfahrung mit Ray hätte ich Ingo nicht zugesagt, ich hätte es mir einfach nicht zugetraut. Zwei meiner ersten Redakteure sind mittlerweile verstorben: Zuerst Michael Wilde, dann Dieter Brors. Der dritte im Bunde, Detlef Grell, ist im Ruhestand. Aber ich bin Heise stets verbunden geblieben. Ich denke "wir", nicht "die".

Alles beginnt mit Menschen. So auch mit Konstantin Klein, der mich bat, doch etwas für die Deutsche Welle zu schreiben. Ich denke auch an viele Kollegen der damals noch großen Computerwoche. Aus dem untergehenden Schiff OS/2 Inside habe ich Jürgen Kuri zu Heise gelockt, der sich ohne Ermutigung auch nicht getraut hätte. Heute ist er immer noch mein Fels in der Brandung.

Sagte ich schon, dass alles mit Menschen beginnt? Vor drei Wochen traf ich Matthias Kremp nach langer Zeit wieder. Ich mag seine Art, über Technik zu schreiben. Und wir vereinbarten locker, dass ich auch für ihn arbeiten würde. Nun ergibt sich nächste Woche eine Gelegenheit, damit anzufangen.

Ich kann etwas: Dinge so erklären, dass man sie versteht. Und dazu muss ich mich an den Leser anpassen. Ich habe sehr viel Übung darin, die gleiche Geschichte aus einem ganz anderen Blickwinkel zu erzählen. Ein Anwender versteht andere Dinge als ein Software-Entwickler und der andere Dinge als ein SysAdmin. In Zukunft gibt es also Geschichten für Menschen, die wissen, an welchem Ende ein Lötkolben warm wird, und für solche, die es eher nicht wissen.

Ich freue mich auf diese Herausforderung. Und genau deshalb mache ich das auch. Ich werde nicht mit Geld gezwungen. ;-)

12 Nov 00:02

On David's Windows experiement

I’m on the record that the Surface Laptop is my favorite Windows device for day-to-day use, so I watched DHH’s trial with the Surface Laptop 3 with a lot of interest. David writes:

Apple’s stubborn four-year refusal to fix the terminally broken butterfly keyboard design led me to a crazy experiment last week: Giving Windows a try for the first time in twenty years.

Like myself, he was in the early wave of people really embracing using Mac OS X as a development platform early on. And like a lot of people, he’s incredibly frustrated with the current MacBook Pro keyboard situation. Frustrated enough to spend a week looking at using Windows as a primary development platform.

It didn’t stick for him. Truth be told, I’m not surprised.

My own experience with putting Windows back into my computing life was somewhat of a necessity, thanks to Microsoft becoming my employer. Yes, Microsoft has come a long way and Macs are now more welcome on the internal network. The experience of using a Mac inside Microsoft, however, leaves enough to be desired that I quickly fell into a pattern of working on both Windows and Mac laptops. The Mac for most of my work, and a Surface for the internal stuff that was more comfortable on Windows.

Over the years, the improvements that Microsoft has been making to Windows to help it be a hospitable platform for *nix developers like me has made the experience a lot more viable. Viable enough at this point that I will often leave my MacBook at home and just take the Surface Laptop with me. With the betas of the second-generation Windows Subsystem for Linux (WSL2) and Windows Terminal, as well as some tolerance for the tinkering required to work around sharp edges, such as having git running in Linux use the Windows credential helper, it’s not an uncomfortable working environment anymore.

It takes time and effort, however, to get things sorted. In that way, it feels kind of like Mac OS X did in its first few releases. It’s getting better all the time. It’s even gotten to the point where I can just imagine a world where I’d use Windows over Mac OS X as my primary environment if I stopped working at Microsoft, or somewhere else with a heavy Windows investment.

Which is a real shocker, to be honest.

But it’s not quite there yet. The team working on WSL2 is still hard at work doing the heavy lifting right now. And so, I’m not at all surprised that David didn’t keep his Surface Laptop, especially given his twenty years of platform muscle memory. I am, however, really happy to see that he gave it a spin.

Oh, and to address a couple of David’s points: I do wish the Surface Laptop had the same pixel density as the Surface tablets. It makes the font rendering a lot better. Putting Windows Home on the Surface Laptop 3 is baffling to me as well. And finally, the latest Apple Magic keyboard is my favorite keyboard of all time as well. If they would just put that keyboard into a laptop…

12 Nov 00:01

Twitter Favorites: [JodiesJumpsuit] At any given moment a good 60% of people who think they’re wearing a poppy, aren’t

vermicious knidsuit @JodiesJumpsuit
At any given moment a good 60% of people who think they’re wearing a poppy, aren’t
12 Nov 00:00

Dynalist goes awry? - Lothar Scholz

I agree with the problems of markdown syntax "programming" for most users. Especially when you see how the inline styles bold/italic/underline/strikethrough are often implemented is becomes bad quickly. And if you have to explain people how you escape asterics with backslashes and backslashes with double backslashs a lot people end up leaving.

Thats why i decided to implement my editor as WYSIWYG and only use some of markdown syntax as smart shortkeys, so your hands can stay on the keyboard. Bear and Ulysses have gone the same direction but it is still not good enough WYSIWYG.

And nobody ever came up with good table support. Markdown with images or bullet lists in table cells ... not possible in any markdown program i have tried. A program can input/output this tables but not a human.

Lets remember where Markdown comes from. From programmers who wanted to embedd formated documentation inside of source code files which live in plain text programming environments. They just had no choice but note taking apps have.

12 Nov 00:00

Le mieux est l'ennemi du bien

by peter@rukavina.net (Peter Rukavina)

My friend Elmine, in her post Leer weer langzaam denken, passes on a piece of advice from Frank:

Belangrijk nog om te melden is de tip die ik van Frank kreeg: ook met vijftien minuten per dag kom je verder in een boek. Die tip heeft me in beweging gekregen om aan een eerste boek te beginnen. En wat gebeurd er vervolgens? Ongemerkt lees ik nu zo weer een uur of langer achter elkaar.

Or, machine-translated:

Another important thing to report is the tip I got from Frank: even with fifteen minutes a day you continue in a book. That tip got me moving to start a first book. And what happens next? Unnoticed, I now read for an hour or more in succession.

I’ve found that if I simply make an effort to scatter books around my home and office, I’ll be more likely to pick them up and read them.

And if I pick them up and read them I’m more likely to keep reading them, for far longer than I’d set out to.

This proves a far more effective “I should read more” strategy than trying to conjure up a perfect reading nook and booking out specific reading time.

Put another way: you can’t read a book that’s not in front of you.

11 Nov 23:58

Behringer bringt 303-Clone – für 150 Euro

by Ronny
mkalus shared this story from Das Kraftfuttermischwerk.

Behringer haut kurz vor Weihnachten noch mal richtig einen raus und kündigt einen offensichtlich ziemlich guten Clone der Roland TB-303 an. TD-3 wird das Ding heißen, in drei Farben verfügbar sein und nur 150 Euro kosten. Ich sehe da keinen Grund, das Teil nicht zu kaufen und wette, dass wir in den nächsten Monaten wieder vermehrt Acid-Lines auf den Dancefloors hören werden.


(Direktlink, via Tanith)

Erste Reviews gibt es auch schon – und das sieht doch ganz schön geil aus.


(Direktlink)

11 Nov 23:56

Waterloo-based OpenText to purchase cloud security firm Carbonite

by Aisha Malik

Waterloo-based software company OpenText Corp, announced that it plans to purchase Carbonite in a $1.4 billion USD (approximately 1.8 billion CAD) deal.

Carbonite is a Boston-based cloud backup solutions company that offers software to protect both personal and business data.

OpenText’s shares surged once the company made the announcement. It hopes that its purchase will strengthen its projects and help it to advance in the cloud-based software industry.

Through the acquisition, OpenText will be able to leverage Carbonite’s focus in cloud-based subscription data protection, disaster recovery, and backup. It will also allow the company to enhance its current security offerings.

This is the ninth purchase that OpenText has made towards cloud-computing. The deal is expected to be finalized within 90 days.

Source: CBC News 

The post Waterloo-based OpenText to purchase cloud security firm Carbonite appeared first on MobileSyrup.

11 Nov 23:55

If you strip out the disingenuous 'Boris wants SuperCanada Plus' horseshit, Farage's position is consistent. The Tory party is Ukip. It is the Brexit party. They are the same thing.

by IanDunt
mkalus shared this story from iandunt on Twitter.

If you strip out the disingenuous 'Boris wants SuperCanada Plus' horseshit, Farage's position is consistent. The Tory party is Ukip. It is the Brexit party. They are the same thing.




756 likes, 266 retweets
11 Nov 23:55

Postcards of Portugal

Postcards of Portugal

We went to Portugal earlier this fall. These are some of the postcards I made and sent to people along the way.

Vila Nova de Milfontes

On the road

Faro

On the road again

Evora

Lisbon

Tourism in Lisbon in 2019 is bonkers in a way that makes it easy to be critical. I had the opportunity to visit Lisbon in 2010 and again in 2011 at what felt like the bottom, or near the bottom, of the U-curve that followed the economic bust of 2008. It's not like there were tumbleweeds in the streets, or that no one smiled, but it was clear people were hurting. I find many aspects of Lisbon in 2019 to be unpleasant but ten years ago there was such a tangible unhappiness hanging in the air that it is difficult for me to want to deny today's city some measure of the good times, complicated as they may be these days.

11 Nov 23:55

xkcd-style charts in JavaScript

by Nathan Yau

For xkcd fans, here’s a JavaScript library by Tim Qian that lets you style your charts like xkcd.

There’s something about sketchy, comic-style charts that makes the data feel more approachable. Maybe just because it’s different or looks more casual? I mean, I would use the style sparingly and maybe not in your next business meeting, but it’s kind of fun to mess with. You can also do this in R and Python of course.

Tags: JavaScript, xkcd

11 Nov 23:47

Foundations

x28's New Blog, Nov 11, 2019
Icon

Matthias Melcher writes, "I tried to understand Stephen Downes’s “Philosophical Foundations of Connectivism“. Here is what I excerpted and remixed: below, or better on an interactive map, or in the  transient wiki." What follows is a concept-by-concept exploration from my paper-in-progress, based on my recent presentation of the same name.

Web: [Direct Link] [This Post]
11 Nov 23:47

Aftermath

This was, for the city of Malden where I live, a disastrous local election: not because the outcome was bad — it wasn’t— but because it may well have poisoned Malden politics for years to come.

As the election approached, the dishonesty and unscrupulousness of the mayoral challenger’s campaign increased. Bigotry came into the open, with Facebook allegations that a city council candidate wasn’t a citizen and suggestions that he be reported to the FBI. That gem came from the President of Malden Youth Soccer, and as a result he is the former President of Malden Youth Soccer. Yet nothing at all happened to those who started the smear, or those who cheered him on. They ran exactly the same play two years ago against another Muslim candidate, and again there were no consequences.

There were no consequences when a candidate used Facebook to assert without evidence that a private citizen was mentally ill, just as in an earlier election there were no consequences when a sitting Councillor denounced a Democratic convention delegate for her Wiccan beliefs. There were no consequences for the candidate who praised the white supremacists of Charlottesville, and now he’s ensconced on the School Committee.

We say, Malden is a welcoming city, but we condone bigotry. Bigotry works.

Infamously, after his complaints about a proposed addiction recovery center were roundly denounced by City Councillors, the challenger withdrew his opposition only to revive it just before the election. Even more infamously, illegal campaign literature trying to tie the incumbent Mayor to abortion was cravenly distributed in church parking lots during Mass. Campaign operative shrugged, saying “it might have been anybody!”

A central mystery of this campaign was, how did the challenger expect to govern if he were elected? Facing a City Council that had already repudiated a central argument of his campaign, facing the natural outrage of those whose religion had been smeared, what possibly could be accomplished?

Now we will hear calls for civility and insistence that we all just get along. The left will meekly comply while the right polishes its daggers and perfects its methods. We will be told to “let it go” and we will, while they continue to use local Facebook pages to spread anti-Semitism, to smear their Muslim neighbors, and to slyly warn that new housing will bring more Asians to Malden. It is, of course, proverbial in these circles that adding more Asians to Malden would be a very bad thing.

Great damage has been done — quiet damage, damage that we can pretend to ignore for a few years, but damage nonetheless. If we cannot stand up to lies and to bigotry, we cannot be trusted. Without that trust, we are not a community.

11 Nov 01:03

Space Analogies

by Andrea

Alexander Gerst’s Horizon Blog: Cave Life for Space. “When you ignore some details, it is amazing how similar cave exploration is to going to space. After my experience with CAVES, I can say that, so far, this is the best analogue that I know for astronauts to mentally prepare for space.”

See also ESA: Caves 2019. (YouTube, 5:50min)

“In September 2019 in Slovenia, astronauts from five space agencies around the world took part in ESA’s CAVES training course – Cooperative Adventure for Valuing and Exercising human behaviour and performance Skills.

The six ‘cavenauts’ were ESA astronaut Alexander Gerst, NASA astronauts Joe Acaba and Jeanette Epps, Roscosmos cosmonaut Nikolai Chub, Canadian Space Agency astronaut Joshua Kutryk and Japan’s space agency JAXA’s Takuya Onishi.

The three-week course prepares astronauts to work effectively in multicultural teams in an environment where safety is critical.

As they explored the caves, they encountered caverns, underground lakes and strange microscopic life. They tested new technology and conducted science – much like life on the International Space Station.

Inhospitable and hard to access, caves are untouched worlds and hold many scientific secrets. The astronauts performed a dozen experiments and were on the lookout for signs of life that has adapted to the extremes. They paid special attention to their environment, monitoring air and water quality, and looking for signs of pollution.”

11 Nov 00:58

Scaling in the presence of errors—don’t ignore them

Building a reliable, robust service often means building something that can keep working when some parts fail. A website where not every feature is available is often better than a website that’s entirely offline. Doing this in a meaningful way is not obvious.

The usual response is to hire more DBAs, more SREs, and even more folk in Support. Error handling, or making software that can recover from faults, often feels like the option of last resort—if ever considered in the first place.

The usual response to error handling is optimism. Unfortunately, the other choices aren’t exactly clear, and often difficult to choose from too. If you have two services, what do you do when one of them is offline: Try again later? Give up entirely? Or just ignore it and hope the problem goes away?

Surprisingly, all of these can be reasonable approaches. Even ignoring problems can work out for some systems. Sort-of. You don’t get to ignore errors, but sometimes recovering from an error can look very similar to ignoring it.


Imagine an orchard filled with wireless sensors for heat, light, and moisture. It makes little sense to try and resend old temperature readings upon error. It isn’t the sensor’s job to ensure the system works, and there’s very little a sensor can do about it, too. As a result, it’s pretty reasonable for a sensor to send messages with wild abandon—or in other words, fire-and-forget.

The idea behind fire-and-forget is that you don’t need to save old messages when the next message overrides it, or when a missing message will not cause problems. A situation where each message is treated as being the first message sent—forgetting that any attempt was made prior.

Done well, fire-and-forget is like a daily meeting—if someone misses the meeting, they can turn up the next day. Done badly, fire-and-forget is akin to replacing email with shouting across the office, hoping that someone else will take notes.

It isn’t that there’s no error handling in a fire-and-forget client, it’s that the best method of recovery is to just keep going. Unfortunately, people often misinterpret fire-and-forget to mean “avoid any error handling and hoping for the best”.

You don’t get to ignore errors.

When you ignore errors, you only put off discovering them—it’s not until another problem is caused that anyone even realises something has gone wrong. When you ignore errors, you waste time that could be spent recovering from them.

This is why, despite the occasional counter example, the best thing to do when encountering an error is to give up. Stop before you make anything worse and let something else handle it.


Giving up is a surprisingly reasonable approach to error handling, assuming something else will try to recover, restart, or resume the program. That’s why almost ever network service gets run in a loop—restarting immediately upon crashing, hoping the fault was transient. It often is.

There’s little point in trying to repeatedly connect to a database when the user is already mashing refresh in the browser. A unix pipeline could handle every possible bad outcome, but more often than not, running the program again makes everything work.

Although giving up is a good way to handle errors, restarting from scratch isn’t always the best way to recover from them.

Some pipelines work on large volumes or data, or do arduous amounts of numerical processing, and no-one is ever happy about repeating days or weeks or work. In theory, you could add error handling code, reduce the risk that the program will crash, and avoid an expensive restart, but in practice it’s often easier to restructure code to carry on where it left off.

In other words, give up, but save your progress to make restarting less time consuming.

For a pipeline, this usually entails a awful lot of temporary files—to save the output of each subcommand, and the result of splitting the input up into smaller batches. You can even retry things automatically, but for a lot of pipelines, manual recovery is still relatively inexpensive.

For other long running processes, this usually means something like checkpoints, or sagas. Or in other words, transforming a long running process into a short running one that’s run constantly, writing out the progress it makes to some file or database somewhere.

Over time, every long running process will get broken up into smaller parts, as restarting from scratch becomes prohibitively expensive. A long running process is just that more likely to run into an impossible error—full disks, no free memory, cosmic rays—and be forced to give up.

Sometimes the only way to handle an error is to give up.

As a result, the best way to handle errors is to structure your program to make recovery easier. Recovery is what makes all the difference between “fire-and-forget” and “ignoring-every-error” despite sharing the same optimism.

You can do things that look like ignoring errors, or even letting something else handle it, as long as there’s a plan to recover from them. Even if it’s restarting from scratch, even if it’s waking someone up at night, as long as there’s some plan, then you aren’t ignoring the problem. Assuming the plan works, that is.

You don’t get to ignore errors. They’re inevitably someone’s problem. If someone tells you they can ignore errors, they’re telling you someone else is on-call for their software.

That, or they’re using a message broker.


A message broker, if you’re not sure, is a networked service that offers a variety of queues that other computers on the network can interact with. Usually some clients enqueue messages, and others poll for the next unread message, but they can be used in a variety of other configurations too.

Like with a unix pipe, message brokers are used to get software off the ground. Similarly to using temporary files, the broker allows for different parts of the pipeline to consume and produce inputs at different rates, but don’t easily allow replaying or restarting when errors occur.

Like a unix pipe, message brokers are used in a very optimistic fashion. Firing messages into the queue and moving on to the next task at hand.

Somewhat like a unix pipeline, but with some notable differences. A unix pipeline blocks when full, pausing the producer until the consumer can catch up. A unix pipeline will exit if any of the subcommands exit, and return an error if the last subcommand failed.

A message broker does not block the producer until the consumer can catch up. In theory, this means transient errors or network issues between components don’t bring the entire system down. In practice, the more queues you have in a pipeline, the longer it takes to find out if there’s a problem.

Sometimes that works out. When there’s no growth, brokers act like a buffer between parts of a system, handling variance in load. They work well at slowing bursty clients down, and can provide a central point for auditing or access control.

When there is growth, queues explode regularly until some form of rate limiting appears. When more load arrives, queues are partitioned, and then repartitioned. Scaling a broker inevitably results in moving to something where the queue is bounded, or even ephemeral.

The problem with optimism is that when things do go wrong, not only do you have no idea how to fix it, you don’t even know what went wrong. To some extent, a message broker hides errors—programs can come and go as they please, and there’s no way to tell if the other part is still reading your messages—but it can only hide errors for so long.

In other words, fire-and-regret.

Although an unbounded queue is a tempting abstraction, it rarely lives up to the mythos of freeing you from having to handle errors. Unlike a unix pipeline, a message broker will always fill up your disks before giving up, and changing things to make recovery easy isn’t as straight forward as adding more temporary files.

Brokers can only recover from one error—a temporary network outage—so other mechanisms get brought in to compensate. Timeouts, retries, and sometimes even a second “priority” queue, because head-of-line blocking is genuinely terrible to deal with. Even then, if a worker crashes, messages can still get dropped.

Queues rarely help with recovery. They frequently impede it.

Imagine a build pipeline, or background job service where requests are dumped into some queue with wild abandon. When something breaks, or isn’t running like it is supposed to, you have no idea where to start recovery.

With a background queue, you can’t tell what jobs are currently being run right now. You can’t tell if something’s being retried, or failed, but maybe you’ve got log files you can search through. With logs, you can see what the system was doing a few minutes ago, but you still have no idea what it might be doing right now.

Even if you know the size of a queue, you’ll have to check the dashboard a few minutes later—to see if the line wiggled—before you know for sure if things are probably working. Hopefully.

Making a build pipeline with queues is relatively easy, but building one that the user can cancel, or watch, involves a lot more work. As soon as you want to cancel a task, or inspect a task, you need to keep things somewhere other than a queue.

Knowing what a program is up to means tracking the in-between parts, and even for something as simple as running a background task, it can involve many states—Created, Enqueued, Processing, Complete, Failed, not just Enqueued—and a broker only handles that last part.

Not very well. As soon as one queue feeds into another, an item of work can be in several different queues at once. If an item is missing from the queue, you know it’s either being dropped or processed, if an item is in the queue, you don’t know if it’s being processed, but you do know it will be. A queue doesn’t just hide errors, it hides state too.

Recovery means knowing what state the program was in before things went wrong, and when you fire-and-forget into a queue, you give up on knowing what happens to it. Handling errors, recovering from errors, means building software that can knows what state it is currently operating in. It also means structuring things to make recovery possible.

That, or you give up on on automated recovery of almost any kind. In some ways, I’m not arguing against fire-and-forget, or against optimism—but against optimism that prevents recovery. Not against queues, but how queues inevitably get used.

Unfortunately, recovery is relatively easy to imagine but not necessarily straight forward to implement.

This is why some people opt to use a replicated log, instead of a message broker.


If you’ve never used a replicated log, imagine an append only database table without a primary key, or a text file with backups, and you’re close. Or imagine a message broker, but instead of enqueue and dequeue, you can append to the log or read from the log.

Like a queue, a replicated log can be used in a fire-and-forget fashion with not so great consequences. Just like before, chaos will ensue as concepts like rate-limiting, head-of-line blocking, and the end-to-end-principle are slowly contended with—If you use a replicated log like a queue, it will fail like a queue.

Unlike a queue, a replicated log can aid recovery.

Every consumer sees the same log entries, in the same order, so it’s possible to recover by replaying the log, or by catching up on old entries. In some ways it’s more like using temporary files instead of a pipeline to join things together, and the strategies for recovery overlap with temporary files, too—like partitioning the log so that restarts aren’t as expensive.

Like temporary files, a replicated log can aid in recovery, but only to a certain point. A consumer will see the same messages, in the same order, but if a entry gets dropped before reaching the log, or if entries arrive in the wrong order, some, or potentially all hell can break loose.

You can’t just fire-and-forget into a log, not over a network. Although a replicated log is ordered, it will preserve the ordering it gets, whatever that happens to be.

This isn’t always a problem. Some logs are used to capture analytic data, or fed into aggregators, so the impact of a few missing or out of order entries is relatively low—a few missing entries might as well be called high-volume random sampling and declared a non-issue.

For other logs, missing entries could cause untold misery. Recovering from missing entries might involve rebuilding the entire log from scratch. If you’re using a replicated log for replication, you probably care quite a lot about the order of log entries.

Like before, you can’t ignore errors—you only make things expensive to recover from.

Handling errors like out of order or missing log entries means being able to work out when they have occurred.

This is more difficult than you might imagine.


Take two services, a primary and a secondary, both with databases, and imagine using a replicated log to copy changes from one to another.

It doesn’t seem to difficult at first. Every time the primary service makes a change to the database, it writes to to log. The secondary reads from the log, and updates its database. If the primary service is a single process, it’s pretty easy to ensure that every message is sent in the right order. When there’s more than one writer, things can get rather involved.

Now, you could switch things around—write to the log first, then apply the changes to the database, or use the database’s log directly—and avoid the problem altogether, but these aren’t always an option. Sometimes you’re forced to handle the problem of ordering the entries yourself.

In other words, you’ll need to order the messages before writing them to the log.

You could let something else provide the order, but you’d be mistaken if you think a timestamp would help. Clocks move forwards and backwards and this can cause all sorts of headaches.

One of the most frustrating problems with timestamps is ‘doomstones’: when a service deletes a key but has a wonky clock far out in the future, and issues an event with a similar timestamp. All operations get silently dropped until the deletion event is cleared. The other problem with timestamps is that if you have two entries, one after the other, you can’t tell if there are any entries that came between them.

Things like “Hybrid Logical Clocks”, or even atomic clocks can help to narrow down clock drift, but only so much. You can only narrow down the window of uncertainty, there’s still some clock skew. Again, clocks will go forwards and backwards—timestamps are terrible for ordering things precisely.

In practice you need explicit version numbers, 1,2,3… etc, or a unique identifier for each version of each entry, and a link back to the record being updated, to order messages.

With a version number, messages can be reordered, missing messages can be detected, and both can be recovered from, although managing and assigning those version numbers can be quite difficult in practice. Timestamps are still useful, if only for putting things in a human perspective, but without a version number, it’s impossible to know what precise order things happened in—and that no steps are missing, either.

You don’t get to ignore errors, but sometimes the error handling code isn’t that obvious.

Using version numbers or even timestamps both fall under building a plan for recovery. Building something that can continue to operate in the presence of failure. Unfortunately, building something that works when other parts fail is one of the more challenging parts of software engineering.

It doesn’t help that doing the same thing in the same order is so difficult that people use terms like causality and determinism to make the point sink in.

You don’t get to ignore errors, but no one said it was going to be easy.


Although using things like replicated logs, message brokers, or even using unix pipes can allow you to build prototypes, clear demonstrations of how your software works—they do not free you from the burden of handling errors.

You can’t avoid error handling code, not at scale.

The secret to error handling at scale isn’t giving up, ignoring the problem, or even it trying again—it is structuring a program for recovery, making errors stand out, allowing other parts of the program to make decisions.

Techniques like fail-fast, crash-only-software, process supervision, but also things like clever use of version numbers, and occasionally the odd bit of statelessness or idempotence. What these all have in common is that they’re all methods of recovery.

Recovery is the secret to handling errors. Especially at scale.

Giving up early so other things have a chance, continuing on so other things can catch up, restarting from a clean state to try again, saving progress so that things do not have to be repeated.

That, or put it off for a while. Buy a lot of disks, hire a few SREs, and add another graph to the dashboard.

The problem with scale is that you can’t approach it with optimism. As the system grows, it needs redundancy, or to be able to function in the presence of partial errors or intermittent faults. Humans can only fill in so many gaps.

Staff turnover is the worst form of technical debt.

Writing robust software means building systems that can exist in a state of partial failure (like incomplete output), and writing resilient software means building systems that are always in a state of recovery (like restarting)—neither come from engineering the happy path of your software.

When you ignore errors, you transform them into mysteries to solve. Something or someone else will have to handle them, and then have to recover from them—usually by hand, and almost always at great expense.

The problem with avoiding error handling in code is that you’re only avoiding automating it.

In other words, the trick to scaling in the presence of errors is building software around the notion of recovery. Automated recovery.

That, or burnout. Lots of burnout. You don’t get to ignore errors.

11 Nov 00:54

General Magic

by Rui Carmo

I remember the Newton era and had an inkling of what General Magic was trying to do (there were some screenshots in BYTE at the time), but I had no idea of how prescient they had been and of who they actually were (other than Andy Rubin, whom I had read up on when we were launching Android handsets in Vodafone Portugal).

This is easily the best documentary I watched this year, and heartily recommend it–you will never look at smartphones the same way again, and by the time the end credits roll you’ll be left wondering if something like General Magic will ever happen again in our lifetimes.


Support this site
11 Nov 00:45

Online alternatives to DevonThink? - Smithers



Hey Makana,

I'd advise you check out Slite or Slab. They're billed as "team-based-wikis."

I've switched my team's documentation over from G-docs to Slite. It's a dream. You can anchor link anything, and it has a file manager&#8212;with a sidebar. (Although, the old sidebar was better.)

I'm not sure it's quite what you're looking for but, as it doesn't have OCR, but... it may get you closer to finding your golden goose.
11 Nov 00:27

Three of the Hundred Falsehoods CS Students Believe

by Eugene Wallingford

Jan Schauma recently posted a list of one hundred Falsehoods CS Students (Still) Believe Upon Graduating. There is much good fun here, especially for a prof who tries to help CS students get ready for the world, and a fair amount of truth, too. I will limit my brief comments to three items that have been on my mind recently even before reading this list.

18. 'Email' and 'Gmail' are synonymous.

CS grads are users, too, and their use of Gmail, and systems modeled after it, contributes to the truths of modern email: top posting all the time, with never a thought of trimming anything. Two-line messages sitting atop icebergs of text which will never be read again, only stored in the seemingly infinite space given us for free.

Of course, some of our grads end up in corporate and IT, managing email as merely one tool in a suite of lowest-common-denominator tools for corporate communication. The idea of email as a stream of text that can, for the most part, be read as such, is gone -- let alone the idea that a mail stream can be processed by programs such as procmail to great benefit.

I realize that most users don't ask for anything more than a simple Gmail filter to manage their mail experience, but I really wish it were easier for more users with programming skills to put those skills to good use. Alas, that does not fit into the corporate IT model, and not even the CS grads running many of these IT operations realize or care what is possible.

38. Employers care about which courses they took.

It's the time of year when students register for spring semester courses, so I've been meeting with a lot of students. (Twice as many as usual, covering for a colleague on sabbatical.) It's interesting to encounter students on both ends of the continuum between not caring at all what courses they take and caring a bit too much. The former are so incurious I wonder how they fell into the major at all. The latter are often more curious but sometimes are captive to the idea that they must, must, must take a specific course, even if it meets at a time they can't attend or is full by the time they register.

I do my best to help them get into these courses, either this spring or in a late semester, but I also try to do a little teaching along the way. Students will learn useful and important things in just about every course they take, if they want to, and taking any particular course does not have to be either the beginning or the end of their learning of that topic. And if the reason they think they must take a particular course is because future employers will care, they are going to be surprised. Most of the employers who interview our students are looking for well-rounded CS grads who have a solid foundation in the discipline and who can learn new things as needed.

90. Two people with a CS degree will have a very similar background and shared experience/knowledge.

This falsehood operates in a similar space to #38, but at the global level I reached at the end of my previous paragraph. Even students who take most of the same courses together will usually end their four years in the program with very different knowledge and experiences. Students connect with different things in each course, and these idiosyncratic memories build on one another in subsequent courses. They participate in different extracurricular activities and work different part-time jobs, both of shape and augment what they learn in class.

In the course of advising students over two, three, or four years, I try to help them see that their studies and other experiences are helping them to become interesting people who know more than they realize and who are individuals, different in some respects from all their classmates. They will be able to present themselves to future employers in ways that distinguish them from everyone else. That's often the key to getting the job they desire now, or perhaps one they didn't even realize they were preparing for while exploring new ideas and building their skillsets.

10 Nov 15:32

mapsontheweb: Viking, Moorish and Magyar invasions into Europe...



mapsontheweb:

Viking, Moorish and Magyar invasions into Europe after death of Charlemagne.

10 Nov 15:32

"Men who are unhappy, like men who sleep badly, are always proud of the fact."

“Men who are unhappy, like men who sleep badly, are always proud of the fact.” - |...