Meaning of Leaky Abstraction?

后端 未结 11 1055
面向向阳花
面向向阳花 2020-12-23 02:33

What does the term \"Leaky Abstraction\" mean? (Please explain with examples. I often have a hard time grokking a mere theory.)

相关标签:
11条回答
  • 2020-12-23 03:09

    Wikipedia has a pretty good definition for this

    A leaky abstraction refers to any implemented abstraction, intended to reduce (or hide) complexity, where the underlying details are not completely hidden

    Or in other words for software it's when you can observe implementation details of a feature via limitations or side effects in the program.

    A quick example would be C# / VB.Net closures and their inability to capture ref / out parameters. The reason they cannot be captured is due to an implementation detail of how the lifting process occurs. This is not to say though that there is a better way of doing this.

    0 讨论(0)
  • 2020-12-23 03:14

    The fact that at some point, which will guided by your scale and execution, you will be needed to get familiar with the implementation details of your abstraction framework in order to understand why it behave that way it behave.

    For example, consider this SQL query:

    SELECT id, first_name, last_name, age, subject FROM student_details;
    

    And its alternative:

    SELECT * FROM student_details;
    

    Now, they do look like a logically equivalent solutions, but the performance of the first one is better due the individual column names specification.

    It's a trivial example but eventually it comes back to Joel Spolsky quote:

    All non-trivial abstractions, to some degree, are leaky.

    At some point, when you will reach a certain scale in your operation, you will want to optimize the way your DB (SQL) works. To do it, you will need to know the way relational databases works. It was abstracted to you in the beginning, but it's leaky. You need to learn it at some point.

    0 讨论(0)
  • 2020-12-23 03:16

    Here's an example familiar to .NET developers: ASP.NET's Page class attempts to hide the details of HTTP operations, particularly the management of form data, so that developers don't have to deal with posted values (because it automatically maps form values to server controls).

    But if you wander beyond the most basic usage scenarios the Page abstraction begins to leak and it becomes hard to work with pages unless you understand the class' implementation details.

    One common example is dynamically adding controls to a page - the value of dynamically-added controls won't be mapped for you unless you add them at just the right time: before the underlying engine maps the incoming form values to the appropriate controls. When you have to learn that, the abstraction has leaked.

    0 讨论(0)
  • 2020-12-23 03:20

    I'll continue in the vein of giving examples by using RPC.

    In the ideal world of RPC, a remote procedure call should look like a local procedure call (or so the story goes). It should be completely transparent to the programmer such that when they call SomeObject.someFunction() they have no idea if SomeObject (or just someFunction for that matter) are locally stored and executed or remotely stored and executed. The theory goes that this makes programming simpler.

    The reality is different because there's a HUGE difference between making a local function call (even if you're using the world's slowest interpreted language) and:

    • calling through a proxy object
    • serializing your parameters
    • making a network connection (if not already established)
    • transmitting the data to the remote proxy
    • having the remote proxy restore the data and call the remote function on your behalf
    • serializing the return value(s)
    • transmitting the return values to the local proxy
    • reassembling the serialized data
    • returning the response from the remote function

    In time alone that's about three orders (or more!) of magnitude difference. Those three+ orders of magnitude are going to make a huge difference in performance that will make your abstraction of a procedure call leak rather obviously the first time you mistakenly treat an RPC as a real function call. Further a real function call, barring serious problems in your code, will have very few failure points outside of implementation bugs. An RPC call has all of the following possible problems that will get slathered on as failure cases over and above what you'd expect from a regular local call:

    • you might not be able to instantiate your local proxy
    • you might not be able to instantiate your remote proxy
    • the proxies may not be able to connect
    • the parameters you send may not make it intact or at all
    • the return value the remote sends may not make it intact or at all

    So now your RPC call which is "just like a local function call" has a whole buttload of extra failure conditions you don't have to contend with when doing local function calls. The abstraction has leaked again, even harder.

    In the end RPC is a bad abstraction because it leaks like a sieve at every level -- when successful and when failing both.

    0 讨论(0)
  • 2020-12-23 03:24

    An example in the django ORM many-to-many example:

    Notice in the Sample API Usage that you need to .save() the base Article object a1 before you can add Publication objects to the many-to-many attribute. And notice that updating the many-to-many attribute saves to the underlying database immediately, whereas updating a singular attribute is not reflected in the db until the .save() is called.

    The abstraction is that we are working with an object graph, where single-value attributes and mult-value attributes are just attributes. But the implementation as a relational database backed data store leaks... as the integrity system of the RDBS appears through the thin veneer of an object interface.

    0 讨论(0)
  • 2020-12-23 03:24

    Leaky abstraction is all about encapsulating state. very simple example of leaky abstraction:

    $currentTime = new DateTime();
    
    $bankAccount1->setLastRefresh($currentTime);
    $bankAccount2->setLastRefresh($currentTime);
    $currentTime->setTimestamp($aTimestamp);
    
    class BankAccount {
        // ...
    
        public function setLastRefresh(DateTimeImmutable $lastRefresh)
        {
            $this->lastRefresh = $lastRefresh;
        } }
    

    and the right way(not leaky abstraction):

    class BankAccount
    {
        // ...
    
        public function setLastRefresh(DateTime $lastRefresh)
        {
            $this->lastRefresh = clone $lastRefresh;
        }
    }
    

    more description here.

    0 讨论(0)
提交回复
热议问题