Chapter Seventeen, in which the frontend developers of Uprock move from GTA to alternative ways of using YouTube and the practical application of the actor model.
What do we love in GTA? The ability to
beat an innocent person to hijack a car, rob a bank, fly a helicopter, plane or jetpack, and, of course, listen to the radio with good music. In general, most people do not mind to arrange it in real life, but from the entire list only good music is legal
and that is not always, according to record companies .
')
And yes, we, like real fans, having passed GTA 5 launched
GTA Radio with a set of all radio stations from all parts of this wonderful game. Enjoy
everything for you , and for those who are interested to make a similar player, please under the cat.
In the case of GTA, it was necessary to see a couple of controversial issues with the copyright and the storage of music. Yes, it would be convenient to simply make a player to mp3, but first it would be necessary to decide how to make a quick download, and secondly - what to do if the copyright holders want to write to us. YouTube came to the rescue: it gives and storage of music, and settles all issues with copyright. You just had to gently hide the player so that it does not hang out before your eyes. Naturally, this gave a small number of problems: there was a little more traffic for end users, mobile devices ceased to be supported, and, unfortunately, safari 7 with its cunning power saving settings.
The YouTube player has a rather inconvenient, but quite functional API: in addition to controlling the volume, position in the track, start-pause, it turned out that there is still the possibility of replacing the currently playing track via loadVideoByUrl. At first, we simply re-created the instance for each new track, but this significantly altered the memory, and only then realized to check the documentation and find a way not to restart the flash for each new track.
There are more than one hundred guides on how to use your YouTube player on the Internet, so there’s really no point in retelling how their player’s approach to browser events and native events differs, how to start and end a track, how to catch when a player really ready and can play and so on - this has all been discussed a hundred times by people who have used YouTube to create their own video sites.
Another thing is important: that few people used it for an audio player. Although the opportunity is really good: YT has really fast loading (thanks for CDN all over the world), seemingly good codecs, excellent compression (if you don’t let the video, but the static image - the song fits in a few MB without serious loss in quality) , and he also gives the opportunity to remove a bunch of questions from the owners,
more precisely, to shift them to Google .
We at
Uprock do not like to do a simple backend, if we do it, then something global, solid, weighty, high-load there, or integration with the real world, but simply storing data is actually much simpler in JSON. Therefore - yes, there is an admin panel, but it edits JSON, which connects directly through browserify for faster page loading, so formally there is no backend on it. But there is nginx, which on any non-existent page gives index.html, in which the magic begins.
On the frontend, we often have an honest Stateless reigning here and now: absolutely everything on the site is resolved through routing (thanks page.js). Why is this cool? Yes, because instead of catching events, the developer simply puts the usual links, such as a transition to this:
<a href="/GTA-San-Andreas">GTA San Andreas</a>
Turn on a random radio from GTA San Andreas, and at the same time change the background. Although not really. The only thing that will make the transition on this link - it vytsepit the names of all stations in the list of radio for GTA San Andreas, and then will transfer the user to a random space, for example,
Radio X Do you think music will start playing there? No, they did not guess. The controller for the radio also simply makes a redirect, already to, say,
Faith No More, and even then the background will change, and the music will start playing.
Why do you need it? First, it isolates the code well. The part of the code that deals with the random selection of the station and the track does not interact with the part of the code associated with the render. They can not influence each other, each part is engaged in its own business. Secondly, it makes the code more logical. If you cut out some of the details related to the render, alerts, remembering the last playing track, and so on - the whole code looks like this (the transition between pages is changed to document.location.hash for readability):
page('/:game/:station/:track', function (ctx, next) { var track = trackDetector(ctx.params); if (ctx.path != getTrackUrl(track)) return next();
If the last part is incomprehensible to someone, it can be rewritten as
page('/:game/:station/:track', function(){ document.location.hash = getTrackUrl(trackDetector(ctx.params)); }); page('/:game/:station', function(){ document.location.hash = getTrackUrl(trackDetector(ctx.params)); }); page('/:game', function(){ document.location.hash = getTrackUrl(trackDetector(ctx.params)); }); page('/', function(){ document.location.hash = getTrackUrl(trackDetector(ctx.params)); });
As a result, we get a universal logical scenario: if a suitable track is not found, we try to go down to the station, to the game, then to the root, and if the suitable track does not exist, we make the transition to any randomly suitable track.
In reality, what happens here is called the actor model.
Why is it really necessary? This gives us the opportunity to rely on the fact that the desired track exists, and make the transition to / GTA-San-Andreas / Radio-X, knowing that the track will not be found, but the error will be intercepted, and we will find some A suitable track from Radio X.
What would it look like in normal code? Well, something like this:
page('/:game', function(ctx){ if (glob.games[ctx.params.game]) { document.location.href = '/'+ctx.params.game+'/'+glob.games[ctx.params.game].stations.getRandom(); } else { document.location.href = '/'+glob.games.getRandom()+'/'; } })
Tell me honestly, do not you think that this is somehow bloated and inefficient?
And now let's get a little into the theory. The model of actors was invented in the seventies for maximum efficiency of parallel computations. Then the computers were not only large, but also connected to large networks spread across the country. About this time there is a wonderful, relatively short story of Stanislav Lem "137 seconds." There is a very clear understanding of how weak individual machines were, and how much people wanted to believe that by combining them all into one big network, they would get something incredible, for example, a prediction of the future.
The meaning is very simple: there are autonomous entities that may or may not work. They respond to incoming connections and can exchange messages with other entities they know about.
This is not to say that it was a bad idea, autonomous parrellelism is experiencing another birth every time another technology for parallel computing appears.
On the actors, text quests were built: the user focus was exchanged between the actors, each actor corresponded to a specific location. All of them existed simultaneously, and in the Unreal Engine any full-fledged entity, be it npc or a wall, is an actor, an autonomous element.
But text quests are actually a special case of the so-called abstract automaton. Actors are used in a huge number of tasks, ranging from modeling the behavior of groups and ending with a web server: each of the actors corresponds to its resource, and simply processes incoming messages, if necessary, passing them on.
But how does the actor really differ from just another parallel process in the system? Firstly, it does not have to be in the system and does not have to be parallel: the actors just exchange messages. Whether they are on the same machine or not, whether they are processed sequentially or in parallel is unimportant. Moreover, this is a mandatory requirement for the model of actors: the developer should not expect messages to come in turn. Only implementation is allowed (but not required), which guarantees that the messages that actor 1 sends to actor 2 will come in the same order as they were sent.
So, we got to the most interesting: why it is needed.
Imagine, you are a front-end vendor, and you finally began to feel that your “big” application can no longer remain whole: you have forgotten to create directives or widgets, are tired of arranging the structure of the entire application and combing it. You finally began to feel that your application should have a microkernel, stand-alone components, and a pubsub data exchange model. What else can you give what you know about the actors?
Imagine that each of the router controllers does not have direct access to external data. Generally it does not have: you can initialize it with some standard data set, and indicate that, if necessary, it can make requests to some other actors (for example, a database).
Why is it important?
Because now the controller can not affect the state of the application. This is an autonomous entity whose behavior is rigidly clogged, which can be guaranteed to be covered with tests, and which the application cannot influence.
Welcome to functional JavaScript.
No, this is not a Haskell or a rock: an actor may have an internal state. But do you need it in the routing, for example? In most cases, no: default controllers should be stateless.
But this is the very same functional that many people are so afraid of trying to build a complex OOP in javaScript, for example, by coming from java. They don’t go to a foreign monastery with their samovar, but many try, yes.
But the model of actors is not necessarily fully implemented (although it often costs).
Yes, we can write something like
page.on('*', function(ctx){WebActors.send(WebActors.ANY, ctx.params)}); WebActors.spawnWorker(function(){ WebActors.receive(['GTA-san-andreas'], function(){
But do you need it? Yes, it looks cool, perceived, perhaps, even steeper, but in reality, it is often not very convenient. It is often much easier to simply keep in mind that each callback listener is a worker who possesses some kind of data (objects, functions, constants) that are clogged into it during initialization, and an internal state. And the maximum that he can do is work with a single interface: render, audio, canvas, essence in WebGL. All the rest he can do only by exchanging "messages" with other actors and the mediator - an actor who resolves all other actors.
Generally speaking, formally speaking, web components are the same actors: autonomous entities that can be pulled for methods and attributes. Doesn’t it resemble something?
The frontend is slowly moving to become more autonomous. If you are a frontend developer, you do not need to use the model of actors, but you should at least try and feel it.
There is an old phrase that any developer should try OP, OOP, forth, and so on. Now I would add the model of actors to this list, especially if you are a web developer.