What does "Decoupling Implementation Details" mean regarding encapsulation in JavaScript? - javascript

I'm reading a blog post regarding encapsulation, after reading it I think I get what encapsulation is and why we need to use it, but at the end, the author talks about what are the advantages of encapsulation and he lists "Decoupling Implementation Details" as one of the benefits of using encapsulation.
I'm quoting it here:
Since Encapsulation enables operating on data using a public interface, it is easier to update the implementation because the tight coupling is eliminated. This is an excellent way to always code against an interface. This also means that with Encapsulation, the object is scalable to accommodate future changes without breaking compatibility.
The Coupling means the extent to which two modules are dependent on each other. Decoupling refers to eliminating such dependencies.
I'm trying to work this out in my head, and thought that maybe a SO member could help me understand what he is talking about. Can someone explain this to me?
Thanks in advance!

Encapsulation is a conscious decision to give your code - your implementation of some functionality - a particular interface, such that the consumer of your implementation only assume what they have to.
I'll start with a non-JS example, but will show one at the end.
Hostnames are an interface. IP addresses are implementation details.
When you go to Stack Overflow, you go to stackoverflow.com, you don't go to 151.101.193.69. And if you did go to 151.101.193.69, you'd notice that it's a Fastly CDN address, not a Stack Overflow address.
It's likely that when Stack Overflow just started, it implemented its web access using its own server, on a different IP address, say, for example, 198.51.100.253.
If everyone bookmarked 198.51.100.253, then when Stack Overflow started using Fastly CDN, suddenly everyone who bookmarked it - millions of people - would have to adjust.
That is a case of broken compatibility, because those millions of people would have been coupled to the IP address 198.51.100.253.
By encapsulating the IP address 198.51.100.253 - the actual detail of the implementation of web access - behind only the thing that users need to know - the name of the website - stackoverflow.com - the public interface, Stack Overflow was able to migrate to Fastly CDN, and all those millions of users were none the wiser.
This was possible because all these users were not coupled to the IP address 198.51.100.253, so when it changed to 151.101.193.69, nobody was affected.
This principle applies in many areas. Here are some examples:
Energy: You pay for electricity. The supplier can provide it using coal, gas, diesel, nuclear energy, hydro, they can change it from one to the other, and you're none the wiser, you're not coupled to hydro, because your interface is the electric socket, not a generator.
Business: When an office building gets cleaning company to keep the building clean, they only have a contract with the company; They cleaners get hired and fired, their salary changes, but that's all encapsulated by the cleaning company and does not affect the building.
Money: You don't need money, you need food and shelter and clothes. But those are implementation details. The interface you export to your employer is money, so they don't have to pay you in food, and if you change your diet or style, they don't have to adjust what food or clothes they buy you.
Engineering: When an office building gets HVAC, and it breaks, the owner just calls the HVAC company, they don't try to fix it themselves. If they did, they void the warranty, because the HVAC company can't guarantee good product if someone else touches the HVAC. Their public interface is the maintenance contract and the HVAC user-facing controls - you're not allowed to access the implementation directly.
And of course, software: Let's say you have a distributed key-value store which has the following client API:
client = kv.connect("endpoint.my.db");
bucket = crc(myKey)
nodeId = bucket % client.nodeCount();
myValue = client.get(nodeId, bucket, myKey);
This interface:
allows the caller to directly and easily find the node which will store the key.
allows the caller to cache bucket information to further save calls.
allows the caller to avoid extra calls to map a key to a bucket.
However, it leaks a ton of implementation details into the interface:
the existence of buckets
the usage of CRC to map keys to buckets
the bucket distribution and rebalancing strategy - the usage of bucket % nodeCount as the logic to map buckets to nodes
the fact that buckets are owned by individual nodes
And now the caller is coupled with all these implementation details. If the maintainer of the DB wants to make certain changes, they will break all existing users. Examples:
Use CRC32 instead of CRC, presumably because it's faster. This would cause existing code to use the wrong bucket and/or node, failing the queries.
Instead of round-robin buckets, allocate buckets based on storage nodes' free space, free CPU, free memory, etc. - that breaks bucket % client.nodeCount() - likewise leads to wrong bucket/node and fails queries.
Allow multiple nodes to own a bucket - requests will still go to a single node.
Change the rebalancing strategy - if a node goes down, then nodeCount goes from e.g. 3 to 2, so all the buckes have to be rebalanced such that bucket % client.nodeCount() finds the right node for that bucket.
Allow reading from any node instead of the bucket owner - requests will still go to a single node.
To decouple the caller from the implementation, you don't allow them to cache anything, save calls, or assume anything:
client = kv.connect("endpoint.my.db");
myValue = client.get(myKey);
The caller doesn't know about CRC, buckets, or even nodes.
Here, the client has to do extra work to figure out which node to send the request to. Perhaps with Zookeeper or using a gossip protocol.
With this interface:
Hashing logic e.g. CRC isn't hard-coded in the caller, it's on the server side and changing it won't break the caller.
Any bucket distribution strategy is likewise only on the server side.
Any rebalancing logic is likewise not in the client.
Even other changes are possible by just upgrading the client, but not changing any code in the caller:
Allow multiple nodes to own a bucket
Read from any node (e.g. choosing the one with the lowest latency).
Switching from a Zookeeper-based node finding infrastructure to a gossip-based one.

Let's take the Map class as an example. it has an API for adding key/value entries to the map, getting the value for a key, etc. You don't know the details of how the Map stores its key/value pairs, you just know that if you use set with a key, then later do get with the same key, you'll get back the value. The detail of the implementation are hidden from you, and largely don't matter to your code.¹ That's an example of how encapsulation decouples the API from the implementation details.
¹ You do know a little bit about the implementation in this specific example: The specification say "Maps must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of elements in the collection." So you know that a Map isn't implemented as (say) an array of key/value pairs, because that implementation wouldn't offer sublinear access times on the number of elements. But you don't know if it's a hash table or B-tree or what. Those are implementation details.

Related

How do you destroy keys with Subtle's cryptography API?

In the WebCrypto/Subtle crypto API, you can generate keys and whatnot. However there appears to be a distinct lack of .destroyKey() or something of the sort.
Are keys cleaned up upon their reference count reaching zero or something of the sort? Is there no way to explicitly destroy/remove a key from memory?
Note that my concern isn't one of security as I know this wouldn't give much of a security benefit, though I am worried about resource leaks and the like. It feels weird not being able to clean up after one's self explicitly.
The Web Cryptography Specification writes:
Authors should be aware that this specification places no normative requirements on implementations as to how the underlying cryptographic key material is stored. The only requirement is that key material is not exposed to script, except through the use of the exportKey and wrapKey operations.
This specification places no normative requirements on how implementations handle key material once all references to it go away. That is, conforming user agents are not required to zeroize key material, and it may still be accessible on device storage or device memory, even after all references to the CryptoKey have gone away.
That is, a user agent may chose to discard the key data as soon as its CryptoKey becomes eligible for garbage collection, but may also choose to keep the data around longer, for instance until the entire browsing context is discarded upon navigating to a different page or closing the browser tab.
In practice, the difference is unlikely to matter: You can fit thousands if not millions of keys in the memory of any web-capable device, so exhausting memory due to delayed collection of key material is exceedingly unlikely. And since browser implementers have an incentive to keep memory usage low, most will choose to free key material upon collection of the CryptoKey.

Confusion regarding bounded contexts and interaction between them

I'm trying to implement my first domain driven application, after going through Eric Evan's book on Domain-Driven Design. I'm a bit confused on how to go about this.
In my application, a user can purchase a service for getting them certain number of views on a video they post in Youtube, which is fulfilled by the other users of my app who watch those videos(Basically a replica of the many youtube promoter apps already available, for learning).
Say the service is represented in the app as an entity called WatchTime aggregate. The WatchTime entity contains some information like the id of user who purchased this service, the max number of views purchased, number of views already fulfilled, and points earned by someone who views the video once.
I decided to go with 3 bounded contexts, one for authentication, one for handling the watchtimes, like adding or removing them, and one for managing users and their data. Now the user has his personal info and some points that he collected while using the application.
At first I was thinking that all the user data and related actions be in the 3rd context, like adding more points to a user and or reducing his points, but then while making the model, I realized that that if the watch time purchasing service is going to be in the second one, then its going to have to communicate to the third one every time a WatchTime is purchased to tell a service there to reduce points for that purchase. It wouldn't make sense to keep them in two different ones.
So instead what I'm thinking of is have a model of the user in the 2nd bounded context, but with only points and the WatchTimes that this user purchased, so now it doesnt have to call something on the 3rd context.
My question is how to properly seperate things into contexts? Is it like based on the models, or should it be based on the functionality, and all models related to those functionality are going to be in the same context?
And another thing, how to ensure that all the objects of the same entity have the same value and properly persisted in the database? Should only one object representing a particular entity be present at a time, which will be persisted and disposed by the end of a function? Because I was thinking that if two objects representing the same entity be present at the same time, there's a possibility of both having different values or changing to different values.
If i sound like im rambling, please let me know if I have to be more clear. Thanks.
Bounded contexts basically define areas of functionality where the ubiquitous language (and thus the model) are the same. In different bounded contexts, "user" can mean different things: in a "user profile" context, you might have their email address but in the "viewing time" context, you'd just have the points granted and viewership purchased.
Re "another thing", in general you need to keep an aggregate strongly consistent and only allow an update to succeed if the update is cognizant of every prior update which succeeded, including any updates which succeeded after a read from the datastore. This is the single-writer principle.
There are a couple of ways to accomplish this. First, you can use optimistic concurrency control and store a version number with each aggregate. You then update the aggregate in the DB only if the version hasn't changed; otherwise you attempt the operation (performing all the validations etc.) against the new version of the aggregate. This requires some support in the DB for an atomic check of the version and update (e.g. a transaction).
An alternative approach (my personal preference) is to recognize that a DDD aggregate has a high level of mechanical sympathy to the actor model of computation (e.g. both are units of strong consistency). There are implementations of the actor model (e.g. Microsoft Orleans, Akka Cluster Sharding) which allow an aggregate to be represented by at most one actor at a given time (even if there is a cluster of many servers).

Storing in MySQL vs JavaScript Object

I have a set of data associating zipcodes to GPS coordinates (namely latitude and longitude). The very nature of the data makes it immutable, so it has no need to be updated.
What are the pro and cons of storing them in a SQL database vs directly as a JavaScript hashmap? The table resides on the server, it's Node.js, so this is not a server vs browser question.
When retrieving data, one is sync, the other async, but there is less than 10k elements, so I'm not sure whether storing these in MySQL and querying them justifies the overhead.
As there is no complex querying need, are there some points to consider that would justify having the dataset in a database?
* querying speed and CPU used for retrieving a pair,
* RAM used for a big dataset that would need to fit into working memory.
I guess that for a way bigger dataset, (like 100k, 1M or more), it would be too costly in memory and a better fit for the database.
Also, JavaScript obejects use hash tables internally, so we can infer they perform well even with non trivial datasets.
Still, would a database be more efficient at retrieving a value from an indexed key than a simple hashmap?
Anything else I'm not thinking about?
You're basically asking a scalability question... "At what point do I swap from storing things in a program to storing things in a databse?"
Concurrency, persistence, maintainability, security, etc.... are all factors.
If the data is open knowledge, only used by one instance of one program, and will never change, then just hard code it or store it in a flat file.
When you have many applications with different permissions calling a set of data and making changes, a database really shines.
Most basically, an SQL database will [probably ...] be "server side," while your JavaScript hash-table will be "client side." Does the data need to be persisted from one request to the next, and between separate invocations of the JavaScript program? If so, it must be stored ... somewhere.
The decision of whether to use "a hash table" is also up to you: hash tables are great when you are looking for explicit keys. But they're not the only data-structure available to you in JavaScript.
I'd say: carefully work out all the particulars of your exact situation, and use these to inform your decision. "An online web forum like this one" really can't step into your shoes on this. "You're the engineer ..."

How to make an array from a string by newline in JavaScript?

I've got this:
var quoted_text = window.getSelection;
For example:
Accepting the Terms of Service
The Stack Exchange Network (the “Network”) is a set of related
Internet sites and other applications for questions and answers, owned
and operated by Stack Exchange Inc. (“Stack Exchange”), a Delaware
corporation. Please read these terms of service (“Agreement”)
carefully before using the Network or any services provided on the
Network (collectively, “Services”). By using or accessing the
Services, you agree to become bound by all the terms and conditions of
this Agreement. If you do not agree to all the terms and conditions of
this Agreement, do not use the Services. The Services are accessed by
You (“Subscriber” or “You”) under the following terms and conditions:
1. Access to the Services
Subject to the terms and conditions of this Agreement, Stack Exchange
may offer to provide the Services, as described more fully on the
Network, and which are selected by Subscriber, solely for Subscriber’s
own use, and not for the use or benefit of any third party. Services
shall include, but not be limited to, any services Stack Exchange
performs for Subscriber, as well as the offering of any Content (as
defined below) on the Network. Stack Exchange may change, suspend or
discontinue the Services at any time, including the availability of
any feature, database, or Content. Stack Exchange may also impose
limits on certain features and services or restrict Subscriber’s
access to parts or all of the Services without notice or liability.
Stack Exchange reserves the right, at its discretion, to modify these
Terms of Service at any time by posting revised Terms of Service on
the Network and by providing notice via e-mail, where possible, or on
the Network. Subscriber shall be responsible for reviewing and
becoming familiar with any such modifications. Use of the Services by
Subscriber following such modification constitutes Subscriber's
acceptance of the terms and conditions of this Agreement as modified.
How can i make in array from that text by newlines?
I need to paste in the begining of each line simbols "> ", how to do that?
Use split()
Fore example
str = "abc\ndef";
console.log(str.split("\n"));
will print out
["abc", "def"]
Use JavaScript .split() function to create an array with elements split by '\n'
and then manually iterate through that array and add '<' for each item. The following code may help :
var str="How\nare\nyou\ndoing\ntoday?";
var n = str.split("\n");
for(var x in n){
n[x]= '>'+n[x];
alert(n[x]);
}

What is the best way to filter spam with JavaScript?

I have recently been inspired to write spam filters in JavaScript, Greasemonkey-style, for several websites I use that are prone to spam (especially in comments). When considering my options about how to go about this, I realize I have several options, each with pros/cons. My goal for this question is to expand on this list I have created, and hopefully determine the best way of client-side spam filtering with JavaScript.
As for what makes a spam filter the "best", I would say these are the criteria:
Most accurate
Least vulnerable to attacks
Fastest
Most transparent
Also, please note that I am trying to filter content that already exists on websites that aren't mine, using Greasemonkey Userscripts. In other words, I can't prevent spam; I can only filter it.
Here is my attempt, so far, to compile a list of the various methods along with their shortcomings and benefits:
Rule-based filters:
What it does: "Grades" a message by assigning a point value to different criteria (i.e. all uppercase, all non-alphanumeric, etc.) Depending on the score, the message is discarded or kept.
Benefits:
Easy to implement
Mostly transparent
Shortcomings:
Transparent- it's usually easy to reverse engineer the code to discover the rules, and thereby craft messages which won't be picked up
Hard to balance point values (false positives)
Can be slow; multiple rules have to be executed on each message, a lot of times using regular expressions
In a client-side environment, server interaction or user interaction is required to update the rules
Bayesian filtering:
What it does: Analyzes word frequency (or trigram frequency) and compares it against the data it has been trained with.
Benefits:
No need to craft rules
Fast (relatively)
Tougher to reverse engineer
Shortcomings:
Requires training to be effective
Trained data must still be accessible to JavaScript; usually in the form of human-readable JSON, XML, or flat file
Data set can get pretty large
Poorly designed filters are easy to confuse with a good helping of common words to lower the spamacity rating
Words that haven't been seen before can't be accurately classified; sometimes resulting in incorrect classification of entire message
In a client-side environment, server interaction or user interaction is required to update the rules
Bayesian filtering- server-side:
What it does: Applies Bayesian filtering server side by submitting each message to a remote server for analysis.
Benefits:
All the benefits of regular Bayesian filtering
Training data is not revealed to users/reverse engineers
Shortcomings:
Heavy traffic
Still vulnerable to uncommon words
Still vulnerable to adding common words to decrease spamacity
The service itself may be abused
To train the classifier, it may be desirable to allow users to submit spam samples for training. Attackers may abuse this service
Blacklisting:
What it does: Applies a set of criteria to a message or some attribute of it. If one or more (or a specific number of) criteria match, the message is rejected. A lot like rule-based filtering, so see its description for details.
CAPTCHAs, and the like:
Not feasible for this type of application. I am trying to apply these methods to sites that already exist. Greasemonkey will be used to do this; I can't start requiring CAPTCHAs in places that they weren't before someone installed my script.
Can anyone help me fill in the blanks? Thank you,
There is no "best" way, especially for all users or all situations.
Keep it simple:
Have the GM script initially hide all comments that contain links and maybe universally bad words (F*ck, Presbyterian, etc.). ;)
Then the script contacts your server and lets the server judge each comment by X criteria (more on that, below).
Show or hide comments based on the server response. In the event of a timeout, show or reveal based on a user preference setting ("What to do when the filter server is down? (show/hide comments with links) ).
That's it for the GM script; the rest is handled by the server.
As for the actual server/filtering criteria...
Most important is do not dare to assume that you can guess what a user will want filtered! This will vary wildly from person to person, or even mood to mood.
Setup the server to use a combination of bad words, bad link destinations (.ru and .cn domains, for example) and public spam-filtering services.
The most important thing is to offer users some way to choose and ideally adjust what is applied, for them.

Categories

Resources