Creating a Pencil Effect in SVG

Scott Turner, who has an entire blog “Exploring procedural generation and display of fantasy maps”, gets into why vector graphics seems on these surface why it would be bad for the look of a pencil stroke:

Something like this pencil stroke would require many tens of thousands of different elements.  Basically each little blob of gray in that image would be separately defined. 

But, SVG filters to the rescue.

It’s all about <feTurbulence>.

Squigglevision!

Direct Link to ArticlePermalink

The post Creating a Pencil Effect in SVG appeared first on CSS-Tricks.

CSS-Tricks

, ,

Emergency Website Kit

Here’s an outstanding idea from Max Böck. He’s created a boilerplate project for building websites that fit within a single HTTP request. This is extremely important for websites that contain critical information for public safety. As Max writes:

In cases of emergency, many organizations need a quick way to publish critical information. But exisiting (CMS) websites are often unable to handle sudden spikes in traffic.

What’s so special about this boilerplate? Well, it does smart stuff like:

  • generates a static site using Eleventy,
  • uses minimal markup with inlined CSS,
  • aims to transmit everything in the first connection roundtrip (~14KB),
  • progressively enables offline-support with Service Workers,
  • uses Netlify CMS for easy content editing, and
  • provides one-click deployment via Netlify to get off the ground quickly

The example website that Max built with this boilerplate is shockingly fast and I would go one step further to argue that all websites should feel as fast as this, not just websites that are useful in an emergency.

Direct Link to ArticlePermalink

The post Emergency Website Kit appeared first on CSS-Tricks.

CSS-Tricks

,
[Top]

How to use CSS Scroll Snap

Nada Rifki demonstrates the scroll-snap-type and scroll-snap-alignCSS properties. I like that the demo shows that the items in the scrolling container can be different sizes. It is the edges of those children that matter, not some fixed snapping distance.

I like Max Kohler’s coverage as well, which includes a demo where the snapping can happen in multiple directions.

This is one of those things where, if you didn’t know about it, it’s worth a solid golf clap for CSS.

Direct Link to ArticlePermalink

The post How to use CSS Scroll Snap appeared first on CSS-Tricks.

CSS-Tricks

,
[Top]

Maintaining Performance

Real talk from Dave:

I, Dave Rupert, a person who cares about web performance, a person who reads web performance blogs, a person who spends lots of hours trying to keep up on best practices, a person who co-hosts a weekly podcast about making websites and speak with web performance professionals… somehow goofed and added 33 SECONDS to their page load.

This stuff is hard even when you care a lot. The 33 seconds came from font preloading rather than the one-line wonder of font-display.

I also care about making fast websites, but mine aren’t winning any speed awards because I’ll take practical and maintainable over peak performance any day. (Sorry, world)

Direct Link to ArticlePermalink

The post Maintaining Performance appeared first on CSS-Tricks.

CSS-Tricks

,
[Top]

Creating an Editable Site with Google Sheets and Eleventy

Remember Tabletop.js? We just covered it a little bit ago in this same exact context: building editable websites. It’s a tool that turns a Google Sheet into an API, that you as a developer can hit for data when building a website. In that last article, we used that API on the client side, meaning JavaScript needed to run on every single page view, hit that URL for the data, and build the page. That might be OK in some circumstances, but let’s do it one better. Let’s hit the API during the build step so that the content is built into the HTML directly. This will be far faster and more resilient.

The situation

As a developer, you might have had to work with clients who keep bugging you with unending revisions on content, sometimes, even after months of building the site. That can be frustrating as it keeps pulling you back, preventing you from doing more productive work.

We’re going to give them the keys to updating content themselves using a tool they are probably already familiar with: Google Sheets.

A new tool

In the last article, we introduced the concept of using Google Sheets with Tabletop.js. Now let’s introduce a new tool to this party: Eleventy

We’ll be using Eleventy (a static site generator) because we want the site to be rendered as a pure static site without having to ship all of the under workings of the site in the client side JavaScript. We’ll be pulling the content from the API at build time and having Eleventy create a minified index.html that we’ll push to the server for the production website. By being static, this allows the page to load faster and is better for security reasons.

The spreadsheet

We’ll be using a demo I built, with its repo and Google Sheet to demonstrate how to replicate something similar in your own projects. First, we’ll need a Google Sheet which will be our data store.

Open a new spreadsheet and enter your own values in the columns just like mine. The first cell of each column is the reference that’ll be used later in our JavaScript, and the second cell is the actual content that gets displayed.

In the first column, “header” is the reference name and “Please edit me!” is the actual content in the first column.

Next up, we’ll publish the data to the web by clicking on File → Publish to the web in the menu bar.

A link will be provided, but it’s technically useless to us, so we can ignore it. The important thing is that the spreadsheet(and its data) is now publicly accessible so we can fetch it for our app.

Take note that we’ll need the unique ID of the sheet from its URL  as we go on.

Node is required to continue, so be sure that’s installed. If you want to cut through the process of installing all of thedependencies for this work, you can fork or download my repo and run:

npm install

Run this command next — I’ll explain why it’s important in a bit:

npm run seed

Then to run it locally:

npm run dev

Alright, let’s go into src/site/_data/prod/sheet.js. This is where we’re going to pull in data from the GoogleSheet, then turn it into an object we can easily use, and finally convert the JavaScript object back to JSON format. The JSON is stored locally for development so we don’t need to hit the API every time.

Here’s the code we want in there. Again, be sure to change the variable sheetID to the unique ID of your own sheet.

 module.exports = () => {   return new Promise((resolve, reject) => {     console.log(`Requesting content from $ {googleSheetUrl}`);     axios.get(googleSheetUrl)       .then(response => {         // massage the data from the Google Sheets API into         // a shape that will more convenient for us in our SSG.         var data = {           "content": []         };         response.data.feed.entry.forEach(item => {           data.content.push({             "header": item.gsx$ header.$ t,             "header2": item.gsx$ header2.$ t,             "body": item.gsx$ body.$ t,             "body2": item.gsx$ body2.$ t,             "body3":  item.gsx$ body3.$ t,             "body4": item.gsx$ body4.$ t,             "body5": item.gsx$ body5.$ t,             "body6":  item.gsx$ body6.$ t,             "body7": item.gsx$ body7.$ t,             "body8": item.gsx$ body8.$ t,             "body9":  item.gsx$ body9.$ t,             "body10": item.gsx$ body10.$ t,             "body11": item.gsx$ body11.$ t,             "body12":  item.gsx$ body12.$ t,             "body13": item.gsx$ body13.$ t,             "body14": item.gsx$ body14.$ t,             "body15":  item.gsx$ body15.$ t,             "body16": item.gsx$ body16.$ t,             "body17": item.gsx$ body17.$ t,                        })         });         // stash the data locally for developing without         // needing to hit the API each time.         seed(JSON.stringify(data), `$ {__dirname}/../dev/sheet.json`);         // resolve the promise and return the data         resolve(data);       })       // uh-oh. Handle any errrors we might encounter       .catch(error => {         console.log('Error :', error);         reject(error);       });   }) }

In module.exports, there’s a promise that’ll resolve our data or throw errors when necessary. You’ll notice that I’m using a axios to fetch the data from the spreadsheet. I like the it handles status error codes by rejecting the promise automatically, unlike something like Fetch that requires monitoring error codes manually.

I created a data object in there with a content array in it. Feel free to change the structure of the object, depending on what the spreadsheet looks like.

We’re using the forEach() method to loop through each spreadsheet column while equating it with the corresponding name we want to allocate to it, while pushing all of these into the data object as content. 

Remember that seed command from earlier? We’re using seed to transform what’s in the data object to JSON by way of JSON.stringify, which is then sent to src/site/_data/dev/sheet.json

Yes! Now have data in a format we can use with any templating engine, like Nunjucks, to manipulate it. But, we’re focusing on content in this project, so we’ll be using the index.md template format to communicate the data stored in the project.

For example, here’s how it looks to pull item.header through a for loop statement:

<div class="listing"> {%- for item in sheet.content -%}   <h1>{{ item.header }} </h1> {%- endfor -%} </div>

If you’re using Nunjucks, or any other templating engine, you’ll have to pull the data accordingly.

Finally, let’s build this out:

npm run build

Note that you’ll want a dist folder in the project where the build process can send the compiled assets.

But that’s not all! If we were to edit the Google Sheet, we won’t see anything update on our site. That’s where Zapier comes in. We can “zap” Google sheet and Netlify so that an update to the Google Sheet triggers a deployment from Netlify.

Assuming you have a Zapier account up and running, we can create the zap by granting permissions for Google and Netlify to talk to one another, then adding triggers.

The recipe we’re looking for? We’re connecting Google Sheets to Netlify so that when a “new or updated sheet row” takes place, Netlify starts a deploy. It’s truly a set-it-and-forget-it sort of deal.

Yay, there we go! We have a performant static site that takes its data from Google Sheets and deploys automatically when updates are made to the sheet.

The post Creating an Editable Site with Google Sheets and Eleventy appeared first on CSS-Tricks.

CSS-Tricks

, , , , ,
[Top]

Consistent Backends and UX: How Do New Algorithms Help?

In previous articles, we explained what consistency is, the difference between “strong” and “eventual” consistency, and why this distinction is more important than ever to modern application developers. We also introduced the notion of ‘consistency tax’: the extra time and effort that a development team needs to invest if they choose a system with only eventual consistency or limited consistency guarantees. 

Several modern databases use state-of-the-art algorithms to eliminate the tradeoff between consistency and performance. Of course, we would not want you to take our word for it without a proper explanation. Therefore, in this final article, we dive into the technical details behind some of these databases. Typically, the only source of information for these technical details are research papers, so the point of this article is to explain these systems in simpler terms.  Because these systems are far more complex in reality, we’ll provide the links in the text in case you want to know more and love to read research papers.

Introduction

In parts 1 and 2 of this article series, we explained how distributed databases use different replicas to spread the load and/or serve users in different regions. To summarize here, for new readers, a replica is just a duplication of your data. And this duplication can live either in the same location for redundancy, or in another location to offer lower latencies to users in those locations. Having multiple replicas that can handle both reads and writes has a strong advantage, because the database becomes scalable and can offer lower latency to all your users, no matter where they are. However, you do not want each of the replicas to have their own interpretation of the data. Instead of small data differences between each replica, you want one unique interpretation of the data, which is often referred to as a single source of truth. In order to achieve that, you need to have some sort of agreement on data changes. We need a consensus. 

Waiting for consensus

Every distributed database that aims to be consistent has multiple replicas that have to agree on the outcome of transactions. If conflicting data updates happen these replicas have to agree which update goes through and which doesn’t. This is called “consensus.”

Let’s go back to our game to exemplify why we need consensus. Imagine that the player of our game only has 3 gold pieces left, but tries to simultaneously buy two different items from two different shops for a total budget larger than the remaining 3 gold pieces. This involves two transactions, one for each item/shop, which we denote as t1 and t2. And let’s pretend that the owners of the shops are across the globe from each other, so the transactions take place on two different replicas. If both of the transactions are accepted the user would be able to buy more than he can afford. How do we prevent the user from overspending?

 An example of two replicas that each receive a transaction (t1) and (t2). If we let both go through it would violate our business rule that users can’t spend more than they own. Clearly these replicas need decide which transaction is allowed and which should be blocked.

We know that these replicas need to communicate in order to agree on the final outcome of the two transactions. What we don’t know is how much communication they need. How many messages have to go back and forth between replica 1 and replica 2 in order to agree which transaction gets priority and which one gets cancelled?

As replicas in a distributed database are meant to serve users from different regions in the world with low latency, they are far apart by nature. By placing duplicates of the data closer to the end users, these users can read with lower latencies. However, when writes happen, the replicas need to send messages to each other to update all duplicated data uniformly–and these messages can take several 10s of milliseconds because they’re bridled by the speed of light as they travel across the globe. It’s clear that we need to keep the number of cross-data center messages as small as possible so that the end user isn’t left waiting around for these replicas across the globe to come to consensus. 

For a long time, it had been thought to be impossible or impractical to do this. But today, several technologies exist to keep the number of round-trips low and bring latency within normal bounds.

The distance between New York and Paris is 5,839 km. For light to travel from New York to Paris and then back again would take 40 milliseconds.

Theoretical vs real-world speed

If it takes a minimum of 40 milliseconds to travel between New York and Paris, a round-trip would take at least 80ms. The most important question that remains is: “How many round-trips do we need to execute transactions?” The answer to this question depends largely on the algorithms that are used.

How to reach agreement? 

It appears that in order to achieve consensus about something, you need at least four hops (or two rounds of communication): one round to let each replica know that you are about to do something, then a second round to actually execute the action once everyone agrees that this action can be executed. This is something called distributed two-phase commit which is used by almost any distributed database. Let’s look at an analogy. Imagine you have to agree with a group of people on a good date for a party. It might go like this:

First, Polly asks everyone if they can make it to a party on Monday; she now knows that everyone can actually come to the party. Next, she needs to let everyone know that the party will indeed be on Monday, and people acknowledge that they will be there.

These are very similar to the two phases in two-phase commit. Of course, databases don’t party so the phases have different functions. In the case of a distributed system, the phases are called: 

  • Prepare or request to commit: make sure that everyone knows about the transaction. In this phase, replicas in a distributed database store the query in some kind of todo list (a transaction log) on the disk to make sure they still know what to do if the server goes down. 
  • Commit: actually calculate the results and store them 

Of course, as always, it’s never that simple. There are many flavors of such algorithms. For example, there are improvements of two-phase commits called Paxos and Raft and even many variants of these (multi paxos/fast paxos/…). These alternatives aim to improve issues of availability or performance. To understand the availability issues, simply imagine that Polly falls sick or Amber’s phone dies. In the former case, she would be unable to continue her work as party coordinator and in the latter case, it would temporarily be impossible for Polly to know whether Amber agrees on the party date. Raft and Paxos improve on this by only requiring the majority to answer and/or selecting a new coordinator automatically when the leader or coordinator goes down. A good animation that shows how Raft works can be found here

Agree about what? 

Can we conclude that each distributed database then requires 2 round trips to write/read data? No, the reality is more complex than that. On one side, there are many possible optimizations and on the other side, there might be multiple things we need to agree on. 

  • Agree on the time of a transaction
  • Agree whether reads can be executed
  • Agree whether reads can be executed

The simplest example that has multiple two-phase commit rounds is probably Cassandra’s light-weight transactions. They first require consensus agreements on reads and then consensus on writes. If each message takes 40ms to travel, this means the entire transaction requires 320ms or longer–depending on the required “locks” as we’ll explain later.

This is fairly easy to understand, but there are some issues with the implementation since Cassandra was never designed to be strongly consistent. Does that mean that strongly consistent databases are even slower? Not at all! Modern distributed databases use a mix of interesting features to achieve better performance.

Waiting for locks

Not only do we need to wait for messages to come to an agreement, but almost every distributed database will also use “locks”. Locks guarantee that the data about to be altered by a transaction is not being simultaneously altered by another transaction. When data is locked, it can’t be altered by other transactions, which means that these transactions have to wait. The duration of such a lock, therefore, has a big impact on performance. Again, this performance impact depends on the algorithm and optimizations that were implemented by the database. Some databases hold locks longer than others and some databases do not use locks at all. 

Now that we know enough basics, let’s dive into the algorithms. 

Modern Algorithms for Consensus

We now know that consensus and locks are the main bottlenecks that we need to optimize. So let’s go back to the main question of this article: “How does new technology lower these latencies within acceptable bounds?” Let’s start off with the first of these modern algorithms, which sparked interesting ideas for the rest of the database world.  

2010 – Percolator

Percolator is an internal system built upon BigTable (one of the early NoSQL databases built by Google) that Google used to make incremental updates to their search index’s page crawling speed.  The first paper on Percolator was released in 2010, inspiring the first distributed database inspired by it: FoundationDB in 2013. FoundationDB then got acquired by Apple to finally release a stable version in 2019, together with the release of a FoundationDB paper.

Although Percolator allowed Google to speed up page crawling significantly, it  was not originally built as a general-purpose database. It was rather intended to be a fast and scalable incremental processing engine to support Google’s search index. Since the search index had to be scalable, many calculations had to happen on many machines concurrently, which required a distributed database. As we learned in the previous articles, programming against distributed systems that store data can be very complex, and traditionally required that developers pay a ‘consistency tax’ to program around unpredictable database behavior. To avoid paying so high a consistency tax, Google  adopted a strong consistency model when they built Percolator. 

The consistency model of Percolator could not exist without two key ingredients: versioning, and the Timestamp Oracle

Ingredient 1: Versioning

As we mentioned in previous articles, strong consistency requires us to agree on a global order for our transactions. Versioning is one of the elements that will be crucial to many of these algorithms since it can be used for failure recovery, to help replicate data, and to support a consistency model called ‘snapshot isolation’.

Versioning helps in failure recovery when a node fails or gets disconnected. When the node comes back online, thanks to the versions, it can easily restore its state by starting at the last snapshot that it was able to save, and then replaying the transactions based on the versions in another node. All it has to do is ask another node: “Hey, what has changed since I was gone?” Without versioning, it would have to copy over all the data, which would have put a huge strain on the system.

Failure recovery is great, but the strongest advantage lies in the fact that such a versioning system can be used to implement a strong consistency model. If the versioning system keeps versions for each data change, we can actually go back in time and do queries against an earlier version of our data.

Some bright minds found out that this historical querying capability could be used to provide a consistency model called ‘snapshot consistency’. The idea of snapshot consistency is to pick a version of the data at the beginning of the query, work with that version of the data during the rest of the query, then write a new version at the end of the query.

There is one possible pitfall here: during the execution of such a query, another query could be writing data that conflicts with the first query. For example, if two write queries start with the same snapshot of a bank account with $ 1000 on it, they could both spend the money since they do not see the writes of the other query. To prevent that, an additional transaction will take place to see if the snapshot’s values changed before either query writes a result. If something conflicting did happen to change the snapshot’s value, the transaction is rolled back and has to be restarted.

However, there is still one problem Percolator needs to solve. Clocks on different machines can easily drift apart a few 100s of milliseconds. If data for a query is split over multiple machines such as in our initial example, you can’t simply ask both machines to give you data at a certain timestamp since they have a slightly different idea of what the current time is. It’s a matter of milliseconds, but when many transactions have to be processed, a few milliseconds are all it takes to go from correct data to faulty data.

Time synchronization brings us to the second Percolator ingredient.

Ingredient 2: The Timestamp Oracle

Percolator’s solution to the time synchronization problem is something called the Timestamp Oracle. Instead of letting each node dictate its own time (which was not accurate enough), Percolator uses a central system that exposes an API providing you with a timestamp. The node on which this system lives is the Timestamp Oracle. When we keep multiple versions of our data, we need at least two timestamps for each query. First, we need a timestamp to query a snapshot, which we will use to read data. Then, at the end of the transaction when we are ready to write, we need a second timestamp to tag the new data version. As a result, Percolator has the disadvantage that it needs at least two calls to the Timestamp Oracle, which introduces even more latency if the Oracle is in another region from the nodes where the calls originated. When Google came up with their Distributed Database Spanner, they solved this problem.  

2012 – Spanner

Spanner was the first globally distributed database to offer strong consistency, which essentially means that you get low latency reads without having to worry about potential database errors anymore. Developers no longer need to invest extra work to circumvent potential bugs caused by eventual consistency. The paper was released in 2012 and it was released to the general public in 2017 as Spanner Cloud.

Ingredient 1: Versioning

Google built Spanner after their experience with Percolator. Since Percolator’s versioning system proved to work, they kept this in Spanner’s design.  This versioning system provided the ability to do very fast reads (snapshot reads) if you were willing to give up consistency. In that case, you could run queries and give Spanner a maximum age of the results. For example: “Please return my current inventory as fast as possible, but the data can only be 15 seconds old”. Basically, instead of abandoning consistency, you could now choose for each query which consistency level suited your use-case. 

Ingredient 2: TrueTime

To eliminate the extra overhead to synchronize time between machines, Spanner abandoned the Timestamp Oracle in favor of a new concept called TrueTime. Instead of having one central system that provides a unified view of time, TrueTime tries to reduce the clock drift between the machines themselves. Engineers at Google managed to limit local clock drift by implementing a time synchronization protocol based on GPS and atomic clocks. This synchronization algorithm allowed them to limit clock drift within a boundary of 7ms, but required specific hardware that consisted of a combination of GPS and Atomic clock technology. 

Of course, there is still a potential clock drift of 7ms, which means that two servers could still interpret a timestamp to be two different snapshots. This is solved by the third ingredient for Spanner: commit-wait. 

Ingredient 3: Commit-wait 

In fact, the TrueTime API does not return one timestamp but returns and interval n which it is sure that the current timestamp should lie. Once it is ready to commit, it will just wait a few milliseconds to cope with the potential drift which is called ‘Commit-wait’. This makes sure that the timestamp that will be assigned to the write is a timestamp that has passed on all nodes. It’s also the reason that running Spanner on commodity hardware can not deliver the same guarantee since the wait period would need to be a few 100s of milliseconds.

2012 – Calvin

The first paper on the Calvin algorithm was released in 2012, from research at Yale. Just like the previous approaches, Calvin consists of several ingredients. Although versioning is also part of it, the rest of the approach is radically different which requires a few extra ingredients to work: deterministic calculations, and the separation of ordering from locking. These are ingredients that are typically not found in databases with traditional architecture. By changing the architecture and accepting that queries have to be deterministic, Calvin can reduce the worst-case number of cross- datacenter messages to two. This pushes down the worst-case latency of global transactions significantly and brings it below 200ms or theoretically even below 100ms. Of course, in order to believe that this is possible, you might want to know how it works first, so let’s take a look at the algorithm.  

Ingredient 1: Versioning

Similar to Percolator and Spanner, Calvin relies on versioned data. These snapshots in Calvin are mainly used to ensure fault-tolerance. Each node stores different snapshots which can be considered as checkpoints. A disconnected node that comes back online only needs to grab the timestamp of the last checkpoint it has witnessed, and then ask another node to inform him of all the transactions that came after that checkpoint. 

Ingredient 2: Deterministic calculations

Many front-end developers will have heard of the Elm frontend framework which implements a React Redux-like workflow. Elm has a steeper learning curve than similar JavaScript-based frameworks because it requires you to learn a new language. However, because the language is functional (no side-effects), Elm allows some impressive optimizations. The key is that functions in Elm give up destructive manipulations to be deterministic. You can run the same function with the same input twice and it will always yield the same result. Because they are deterministic, Elm queries can now more efficiently decide how to update views. 

Similar to Elm, Calvin has given up something to speed up the calculations. In the case of Calvin, we can basically say that the result of a transaction will be the same, whether it’s executed on machine A or Machine B. This might seem evident, but typically databases do not guarantee this. Remember that SQL allows you to use the current time or allows something called interactive transactions where user input can be inserted in the middle of a transaction, both of which could violate the guarantees provided by Calvin. 

To achieve deterministic calculations, Calvin (1) needs to take out calculations such as current time and pre-calculate them, and (2) does not allow interactive transactions. Interactive transactions are transactions where a user starts a transaction, reads some data, provides some additional user input in the middle, and then finally does some extra calculations and possibly some writes. Since the user is not predictable, such a transaction is not deterministic. In essence, Calvin trades in a minor convenience (interactive transactions) for great performance.

Ingredient 3: Separate the problem of ordering.

Databases spend a lot of time negotiating locks in order to make it look like the system is executing in a specific order”. If an order is all you need, maybe we can separate the problem of locking from the problem of ordering. This means though that your transactions have to be pure.

— Kyle Kingsbury

Separating the concern of ordering transactions from the actual execution has been considered many times in the database world but without much success. However, when your transactions are deterministic, separating the ordering from the calculations actually becomes feasible. In fact, the combination of deterministic calculations and the separation of ordering from the rest of the algorithm is extremely powerful since it helps to reduce lock duration and greatly diminishes the slower communication between distant nodes (cross-datacenter communication). 

Shorter lock duration

Whenever locks are held on a piece of data, it means that other queries that use that data have to wait. Therefore, shorter locking results in better performance. Below is an image that shows an overview of the locking procedure in Calvin compared to how a traditional distributed database might do it. Most databases would keep a lock on data until there is at least a consensus on what to write while Calvin would only keep the lock until all nodes agree on the order. Because the calculations are deterministic and they all agreed on the order, each node will calculate separately and come to the same end result.

Less communication between distant nodes

Besides the advantages in lock duration, separating ordering from the rest of the algorithm also requires less communication. As explained before with the Cassandra example, a distributed database typically requires cross-datacenter communication in many phases of their algorithm. In the case of Calvin, the only moment we need to agree on something is at the moment we determine the order. With the Raft protocol, this could be done in two hops which makes it possible to achieve sub 100ms latencies for read-write queries. 

Together with the reduced lock time, this also brings superb throughput. The original Calvin paper has also done experiments that show that this approach significantly outperforms traditional distributed database designs under high contention workloads. Their results of half a million transactions per second on a cluster of commodity machines are competitive with the current world record results obtained on much higher-end hardware.

Run on any hardware

Besides that, Calvin has another advantage: it no longer requires specific hardware in order to obtain such results. Since Calvin can run on commodity machines, it can run on any cloud provider.

2014 – The FaunaDB flavor of Consensus

Ingredient 1: Versioning

FaunaDB has its own distributed transaction protocol with some similarities to Calvin. Just like the former approaches, FaunaDB’s data is also versioned. Since versioning is not only useful for the consistency model but can also have business value, FaunaDB has upgraded this mechanism to a first-class citizen that can be used by end-users. This feature essentially allows time-traveling queries. End-users can execute a query on historic data to answer questions such as: “What would the result of this query have been 20 days ago?”. This is useful to recover data that was accidentally overwritten, audit data changes, or simply incorporate time-travel in your application’s features. 

Ingredient 2 and 3: Deterministic calculations and Separation

Like Calvin, FaunaDB also has deterministic calculations and separates the problem of ordering from the rest of the algorithm. Although there are similarities, calculating transactions in FaunaDB happens in a different phase than Calvin. Where Calvin takes advantage of the deterministic nature to execute the same transaction multiple times once the order is set, FaunaDB will calculate only once prior to consensus on the order of the transactions. Which brings us to the fourth ingredient.

Ingredient 4: Optimistic calculation

FaunaDB adds a fourth ingredient which we have seen already when we talked about Snapshot Isolation: Optimistic calculations instead of locking. 

FaunaDB will not lock, but will instead optimistically calculate the result of the transaction once in the node where the transaction was received, and then add the result and the original input values to the log. Where Calvin would have saved the query that needs to be executed in the transaction log, FaunaDB will save both the result of the calculation and the original input values in the log. Once there is consensus on the order in which the results have to be applied, FaunaDB will verify whether the input data for that calculation has changed or not (thanks to versioning). If the input values have changed, the transaction is aborted and restarted, if they have remained the same, the results are applied on all nodes without any extra calculation.

FaunaDB’s algorithm has similar advantages as Calvin, but reduces the amount of required calculations in the cluster. 

Conclusion

In this series, we have explained how strong consistency can help you build error-free applications more efficiently. In this last article, we have further explained how revolutionary ideas can power a new generation of distributed databases that are both consistent and performant. The takeaway in the previous articles was: “Consistency matters”. In this final article, the takeaway is encompassed in the following:

In the near future, if you read a phrase such as: 

“Many NoSQL databases do not offer atomic writes for multiple documents, and in return give better performance. And while consistency is another great feature of SQL databases, it impedes the ability to scale out a database across multiple nodes, so many NoSQL databases give up consistency.” – the biggest challenges of moving to NoSQL

Realize that modern algorithms enable databases to deliver consistency without centralization. In this article, we have seen a few examples of algorithms and databases that do this. Databases that build upon these algorithms are a next generation of databases that no longer can be described by simple categories such as NoSQL, SQL, or even NewSQL.

With distributed cloud databases based on Percolator, Spanner, Calvin, and FaunaDB’s transaction protocol, you can have highly performant distributed databases that offer stronger consistency models. This means that you can build data-intensive applications that offer low-latency without having to worry about data errors, performance, or service provisioning. In such systems, consistency is transparent, and you do not have to think about it as a developer. The next time you choose a database, pick one that is consistent by default.

The post Consistent Backends and UX: How Do New Algorithms Help? appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]

Get Static

In this piece, Eric Meyer argues that performance is more important than ever right now — especially for websites that contain critical information for the public:

If you are in charge of a web site that provides even slightly important information, or important services, it’s time to get static. I’m thinking here of sites for places like health departments (and pretty much all government services), hospitals and clinics, utility services, food delivery and ordering, and I’m sure there are more that haven’t occurred to me. As much as you possibly can, get it down to static HTML and CSS and maybe a tiny bit of enhancing JS, and pare away every byte you can.

What Eric means by “it’s time to get static” is that we need to serve regular ol’ HTML, CSS, and JavaScript files to the browser with server-side rendering. That way, our sites are faster and with fewer bottlenecks that can render the whole website useless.

On this note, Zach Leatherman recently looked at 200 sites built with Eleventy and found that the mean Lighthouse performance score was 93.7! In other words: static site generators are gosh darn fast. And if that’s not a great reason to make the switch or to start learning about static site generators in general, then I don’t know what is.

Direct Link to ArticlePermalink

The post Get Static appeared first on CSS-Tricks.

CSS-Tricks

[Top]

Add Beautiful Images with the Unsplash API

Perhaps you know Unsplash? I’d wager it’s the most popular stock photography site out there for two big reasons:

  1. Every photo on there is pretty darn nice
  2. Every photo is entirely free even for commercial use. You don’t have to ask permission or even credit it (although that’s appreciated).

Here’s something you might not know though: Unsplash has an API, and it’s unlimited and free. Brass tacks: it’s exactly what you hope it’s going to be. A really clean, well documented, well-performing, JSON API that gives you URLs to photos with metadata.

What would you use the Unsplash API for?

There are lots of examples on Unsplash’s developer area, from Medium to Squarespace to Trello, but here is another one of my favorites!

I use Notion every day. It’s a great app for note-taking, planning, and all sorts of stuff. One of the features it has is giving every document you create within it a custom image header. These give the documents some great personality. Notion has a handful you can choose from or you can upload your own. Or, you can search Unsplash for them!

How does that work? Lemme show you first:

They use the Unsplash API to do it and here’s an article about that. There is a search endpoint as part of the API that makes this quite easy to do.

For example, you’d hit a URL like:

https://api.unsplash.com/search/photos?page=1&query=SEARCH_QUERY

And you’ll get JSON back like:

{   "total": 133,   "total_pages": 7,   "results": [     {       "id": "eOLpJytrbsQ",       "created_at": "2014-11-18T14:35:36-05:00",       "width": 4000,       "height": 3000,       "color": "#A7A2A1",       "likes": 286,       "liked_by_user": false,       "description": "A man drinking a coffee.",       "user": {         "id": "Ul0QVz12Goo",         "username": "ugmonk",         "name": "Jeff Sheldon",         "first_name": "Jeff",         "last_name": "Sheldon",         "instagram_username": "instantgrammer",         "twitter_username": "ugmonk",         "portfolio_url": "http://ugmonk.com/",         "profile_image": {           "small": "https://images.unsplash.com/profile-1441298803695-accd94000cac?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32&s=7cfe3b93750cb0c93e2f7caec08b5a41",           "medium": "https://images.unsplash.com/profile-1441298803695-accd94000cac?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=64&w=64&s=5a9dc749c43ce5bd60870b129a40902f",           "large": "https://images.unsplash.com/profile-1441298803695-accd94000cac?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=128&w=128&s=32085a077889586df88bfbe406692202"         },         "links": {           "self": "https://api.unsplash.com/users/ugmonk",           "html": "http://unsplash.com/@ugmonk",           "photos": "https://api.unsplash.com/users/ugmonk/photos",           "likes": "https://api.unsplash.com/users/ugmonk/likes"         }       },       "current_user_collections": [],       "urls": {         "raw": "https://images.unsplash.com/photo-1416339306562-f3d12fefd36f",         "full": "https://hd.unsplash.com/photo-1416339306562-f3d12fefd36f",         "regular": "https://images.unsplash.com/photo-1416339306562-f3d12fefd36f?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&s=92f3e02f63678acc8416d044e189f515",         "small": "https://images.unsplash.com/photo-1416339306562-f3d12fefd36f?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&s=263af33585f9d32af39d165b000845eb",         "thumb": "https://images.unsplash.com/photo-1416339306562-f3d12fefd36f?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max&s=8aae34cf35df31a592f0bef16e6342ef"       },       "links": {         "self": "https://api.unsplash.com/photos/eOLpJytrbsQ",         "html": "http://unsplash.com/photos/eOLpJytrbsQ",         "download": "http://unsplash.com/photos/eOLpJytrbsQ/download"       }     },     // more photos ...   ] }

So to offer a search experience inside an app like Notion, you’d have a little search form and when users submit that search query, you’d hit the API with the value they entered, then loop over response.results using the response.results.urls.thumb to show the images returned. If the user picks one, you can use a higher-res URL to do something with and have access to all that photos metadata.

Hot tip! The URLs to photos are dynamic in that you can resize them, crop them, serve them in different formats, and even change the compression quality all from URL parameters. For example, changing size is like &w=200.

That is exactly what we do on CodePen

The purpose of CodePen Pen Editor is to provide an online code editor that makes it tremendously easy to code something up for the web, save it, and share it. Images are a big part of the web, so it’s very possible that you might want to use a gorgeous image in a Pen. We have Asset Hosting ourselves on CodePen as a PRO feature, but we also offer Unsplash images to everyone for free!

Check out how it works:

A basic example in React

  • Let’s make a search <form>, when submitted, it hits the Unsplash API and returns a bunch of photos.
  • We’ll use Superagent for the Ajax just to make a smidge easier.
  • We’ll track the current search query and returned data in state.

Here is that working!

How might you use that in your own app?

  • Does your app allow users to create anything? If so, could those things be enhanced by great photos? For example, cover images, background images, images for blog posts, etc. Check out existing partners for more ideas.
  • Could this be part of an avatar-choosing experience?
  • Maybe you could build a plugin that enhances some existing app by allowing quicker access to photos.

Feel free to leave comments with more ideas or how you have used the API. And if you haven’t, try it out.

The post Add Beautiful Images with the Unsplash API appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]

How to Repeat Text as a Background Image in CSS Using element()

There’s a design trend I’ve seen popping up all over the place. Maybe you’ve seen it too. It’s this sort of thing where text is repeated over and over. A good example is the price comparison website, GoCompare, who used it in a major multi-channel advertising campaign.

Nike has used it as well, like in this advertisement:

Diggin’ that orange! (Source)

I couldn’t help but wonder how I would implement this sort of design for the web. I mean, we could obviously just repeat the text in markup. We could also export the design as an image using something like Photoshop, but putting text in images is bad for both SEO and accessibility. Then there’s the fact that, even if we did use actual text, it’s not like we’d want a screen reader speak it out.

Versatility
Versatility
Versatility
Versatility

OK, stop already!

These considerations make it seem unrealistic to do something like this on the web. Then I found myself pining for the long-existing, yet badly supported, element() feature in CSS. It enables the use of any HTML element as a background image, whether it be a single button element, or an entire <div> full of content.

According to the spec:

The element() function only reproduces the appearance of the referenced element, not the actual content and its structure. Authors should only use this for decorative purposes.

For our purposes, we’d be referencing a text element to get that repeating effect.

Let’s define an ID we can apply to the text element we want to repeat. Let’s call it #thingy. Note that when we use #thingy, we’ve got to prefix the element() value with -moz-. While element() has been supported in Firefox since 2010, it sadly hasn’t landed in any other browser since.

.element {   background-image: -moz-element(#thingy); }

Here’s a somewhat loose recreation of the Nike advertisement we saw earlier. Again, Firefox is required to see the demo as intended.

See how that works conceptually? I placed an element (#versatility) on the page, hid it by giving it zero height, set it as the background-image on the body, then used the background-repeat property to duplicate it vertically down the page.

The element() background is live. That means the background-image appearance on the thing using it will change if the referenced HTML element changes. It’s the same sort of deal when working with custom properties: change the variable and it updates everywhere it’s used.

There are, of course, other use cases for this property. Check out how Preethi used it to make in-page scrolling navigation for an article. You could also use a HTML canvas element as a background if you want to get fancy. One way I’ve used it is to show screenshots of pages in a table of contents. Vincent De Oliveira, has documented some wildly creative examples. Here’s an image-reflection effect, if you’re into retro web design:


Pretty neat, right? Again, I wish I could say this is a production-ready approach to get that neat design effect, but things are what they are at the moment. Actually, that’s a good reminder to make your voice heard for features you’d like to see implemented in browsers. There are open tickets in WebKit and Chromium where you can do that. Hopefully we’ll eventually get this feature in Safari-world and Chrome-world browsers.

The post How to Repeat Text as a Background Image in CSS Using element() appeared first on CSS-Tricks.

CSS-Tricks

, , , , ,
[Top]

Value Bubbles for Range Inputs

Range inputs in HTML are like this:

<input type="range" name="quantity" min="1" max="10">

In browsers that support them, they look like this:

Now that’s great and all. You could use it for anything where you want to collect a number from a user that has an enforced minimum and maximum value.

But notice anything weird? All by itself, that range input doesn’t communicate to the user what number they will actually be submitting. Now if your input is something like “How are you feeling? Left for sad, right for happy.” – then fine, you probably don’t need to show the user a number. But I would wager it’s more common that you’ll need to show the number than not show it.

To be fair, the spec says:

The input element represents a control for setting the element’s value to a string representing a number, but with the caveat that the exact value is not important, letting UAs provide a simpler interface than they do for the Number state.

But c’mon, just because we want a cool slider doesn’t automatically mean we should prevent the user from knowing the submitted value. I wouldn’t necessarily say browsers should alter their UI control to show that number. I am saying we should build that ourselves!

This is the perfect use case for the <output> tag, which is specifically for values calculated by form elements. Here is a super simple implementation of how you might use it:

<input type="range" name="foo"> <output for="foo" onforminput="value = foo.valueAsNumber;"></output>

Update! New version with Vanilla JavaScript that also works better.

Our goal here is to display a “bubble” that shows the current value of a range input.

Setting the value of our “bubble” from the value of the input is a matter of pulling the range value and plopping it in the bubble:

range.addEventListener("input", () => {   bubble.innerHTML = rangel.value; });

The trick is positioning the bubble along the range input so it slides alongside the “thumb”. To do that, we’ll need to calculate what % the bubble needs to be scooted to the left. So let’s make a function to do that to keep things a smidge cleaner:

range.addEventListener("input", () => {   setBubble(range, bubble); });  function setBubble(range, bubble) {   const val = range.value;   const min = range.min ? range.min : 0;   const max = range.max ? range.max : 100;   const newVal = Number(((val - min) * 100) / (max - min));   bubble.innerHTML = val;    // Sorta magic numbers based on size of the native UI thumb   bubble.style.left = newVal = "%"; }

Here we’re making sure we account for the range inputs min and max attributes and calculating a % position between 0-100 based on the current value in that range. Not all ranges are the default 0-100 numbers, so say a range was at value 50 in a range of 0 to 200, that would be 25% of the way. This accounts for that.

But it has one annoying flaw: the bubble is too far to the left at the start and too far to the right at the end. On range inputs, the thumb doesn’t hang off the left edge so it’s center is at the start, and same at the end. Like a scrollbar, the edges of the thumb stop within the track.

We can use some magic numbers there that seem to work decently well across browsers:

// Sorta magic numbers based on size of the native UI thumb   bubble.style.left = `calc($ {newVal}% + ($ {8 - newVal * 0.15}px))`;

Here’s that final demo:

I was inspired to poke around with this because reader Max Globa wrote in with their version which I’ll post here:

A cool aspect of Max’s version is that the range input is CSS-styled, so the exact size of the thumb is known. There are some numbers that feel rather magic in the JavaScript math, but at least they are based on real numbers set in the CSS about the size of the thumb.

Other Versions

Dave Olsen ported the (original) idea to not have a dependency on jQuery. Here’s that version:


Sean Stopnik:


simurai:


Vincent Durand:


Don’t forget range input can have datalists which put little notches on them which is kinda cool.


Ana Tudor has a massive collection, many of which indicate the current value through their design.

😬 Old Version from Original Version of this Post (jQuery, plus doesn’t work as well)

Just leaving this in here for historical reasons.

Let’s pull in our friend jQuery and get our CSS on. This goal is below. Any range input, any time, any min/max/step – we put a bubble above it showing the current value.

Let’s style the output element first. We’ll absolutely position it above the input. That gives us the ability to adjust the left value as well, once we figure out with JavaScript what it should be. We’ll fancy it up with gradients and border-radius, and even add a little pointer triangle with a pseudo-element.

output {    position: absolute;   background-image: linear-gradient(top, #444444, #999999);   width: 40px;    height: 30px;    text-align: center;    color: white;    border-radius: 10px;    display: inline-block;    font: bold 15px/30px Georgia;   bottom: 175%;   left: 0;   margin-left: -1%; } output:after {    content: "";   position: absolute;   width: 0;   height: 0;   border-top: 10px solid #999999;   border-left: 5px solid transparent;   border-right: 5px solid transparent;   top: 100%;   left: 50%;   margin-left: -5px;   margin-top: -1px; }

Now what we need to do is watch all range inputs for a change in their value. Our goal is to shift the left position of the bubble in pace with the slider. That’s not the simplest thing in the world, being that sliders can be of any width and any minimum or maximum value. We’re going to have to do a little math. Here’s all the jQuery JavaScript, commented up:

// DOM Ready $ (function() {  var el, newPoint, newPlace, offset;    // Select all range inputs, watch for change  $ ("input[type='range']").change(function() {      // Cache this for efficiency    el = $ (this);        // Measure width of range input    width = el.width();        // Figure out placement percentage between left and right of input    newPoint = (el.val() - el.attr("min")) / (el.attr("max") - el.attr("min"));        // Janky value to get pointer to line up better    offset = -1.3;        // Prevent bubble from going beyond left or right (unsupported browsers)    if (newPoint < 0) { newPlace = 0; }    else if (newPoint > 1) { newPlace = width; }    else { newPlace = width * newPoint + offset; offset -= newPoint; }        // Move bubble    el      .next("output")      .css({        left: newPlace,        marginLeft: offset + "%"      })      .text(el.val());  })  // Fake a change to position bubble at page load  .trigger('change'); });

The one gross part in there is that 1.3 value. I was trying to line up the tip of the bubble’s triangle with the center of the slider. It’s not easy, because the slider’s center is never 100% left or right. That value isn’t perfect, nor perfectly implemented, but it’s better than not having it.

As a bonus, browsers that don’t support the range input still get the bubble action.

The above code depends on the range inputs having a specified min and max value. If they don’t it kinda breaks. I think it would be weird to use a range input without specifying these things, although if you don’t it seems they default to 0 and 100. To bulletproof this, you’d grab each attribute, test it, and if it didn’t look right fix it. Something like:

var minValue, maxValue; if (!el.attr("min")) { minValue = 0; } else { minValue = el.attr("min"); }

…then use the minValue variable in the math. And do similar for max. Anyway, here’s the live demo:

The post Value Bubbles for Range Inputs appeared first on CSS-Tricks.

CSS-Tricks

, , ,
[Top]