Live data from Hacker News

On the criteria to be used in decomposing systems into modules (1972) [pdf]

win.tue.nl

21–30 of 33 posts

Re: On the criteria to be used in decomposing systems into modules (1972) [pdf]

#21
post #19
post #2

> Conclusion We have tried to demonstrate by these examples that it is almost always incorrect to begin the decomposition of a system into modules on the basis of a flowchart. We propose instead that one begins with a list of difficult design decisions or design decisions which are likely to change. Each module is then designed to hide such a decision from the others. Since, in most cases, design decisions transcend…

There are clear cases when the approach advocated in the paper just does not work. For example, one cannot hide behind an abstraction the difference between a reliable local and unreliable network storage. Another problem is that designing module boundaries to minimize the future changes require to anticipate what may change. But as the saying goes, “it is really hard to predict especially about the future”. If the p…

> There are clear cases when the approach advocated in the paper just does not work.

The paper calls for being deliberate in how you modularize your code. So is your alternative to have, what, no modules? To just arbitrarily divide your code between modules?

If you have modules (whatever that means in your language(s)) and you don't consider how to divide your code across them, you're inviting trouble because now you're just being cavalier and avoiding the task of thinking. Not being deliberate is careless.

> For example, in the example in the paper they assumed that the task would stay the same

Yes, he did do that. Both versions, however, largely make this task independent of the modules other than the master control module by putting the KWIC task into master control module itself. All the other modules facilitate the KWIC task and the master control module plumbs it all together. In either design, a change in the task will require changes to a variety of modules but will require changing at least the master control module in both cases. How many other changes are needed? Who knows! Depends on how big a change we're making to the task.

The second design, though, leaves the facilitating modules more independent of each other, in a "what do they have to know about each other" sense. The line storage is presented as an interface, none of the other modules have to know how it works, just how to work it. This is in sharp contrast to the first design, where the line storage model is explicitly known by each of the several modules, and any change to it requires changing most of the program.

Re: On the criteria to be used in decomposing systems into modules (1972) [pdf]

#22
post #17
post #14

I always bring up this paper when I read a post criticizing OOP. It's a bit old but still very relevant and practical. In it the concept of information hiding, closely related to encapsulation, was first described. This concept plays a central role in the strategy for effective system modularization and is IMHO the basis of OOP. Shameless plug: A couple of years ago I wrote a post about this paper trying to expand it…

I don't remember seeing a criticism of OOP that is a criticism of encapsulation. Everybody tends to agree that encapsulation is desirable. It seems to me criticisms of OOP are that it rolls too many things into one construct, the class: it's a type, with encapsulation of methods and data structure, plus inheritance, all into one. And it can lead to not so efficient data placement on modern CPU (AoS vs SoA). Languages…

I think Clojure quite explicitly rejects "encapsulationism". As does the "data on the outside" philosophy of event driven systems.

Re: On the criteria to be used in decomposing systems into modules (1972) [pdf]

#23
post #19

Earlier quoted context omitted.

There are clear cases when the approach advocated in the paper just does not work. For example, one cannot hide behind an abstraction the difference between a reliable local and unreliable network storage. Another problem is that designing module boundaries to minimize the future changes require to anticipate what may change. But as the saying goes, “it is really hard to predict especially about the future”. If the p…

> There are clear cases when the approach advocated in the paper just does not work. The paper calls for being deliberate in how you modularize your code. So is your alternative to have, what, no modules? To just arbitrarily divide your code between modules? If you have modules (whatever that means in your language(s)) and you don't consider how to divide your code across them, you're inviting trouble because now you…

My experience is that anticipating future requirement changes do not work in general. So do not reflect in the design including the design of module boundaries the current assumptions about the future. Focus instead on other criteria, like reducing complexity or making the design more transparent.

Re: On the criteria to be used in decomposing systems into modules (1972) [pdf]

#24

I really thought there had been a previous submission with more comments, but maybe it was another Parnas paper. The only past submission with comments: https://news.ycombinator.com/item?id=8849468 - Jan 7, 2015 (5 comments)

A Rational Design Process: How and Why to Fake It https://news.ycombinator.com/item?id=11101358

From Feb 2016, with just 2 comments. The paper is much better than the comments would suggest.

Re: On the criteria to be used in decomposing systems into modules (1972) [pdf]

#25
post #23

Earlier quoted context omitted.

> There are clear cases when the approach advocated in the paper just does not work. The paper calls for being deliberate in how you modularize your code. So is your alternative to have, what, no modules? To just arbitrarily divide your code between modules? If you have modules (whatever that means in your language(s)) and you don't consider how to divide your code across them, you're inviting trouble because now you…

My experience is that anticipating future requirement changes do not work in general. So do not reflect in the design including the design of module boundaries the current assumptions about the future. Focus instead on other criteria, like reducing complexity or making the design more transparent.

I think I get what you're saying and there's merit to it. However, it appears to me that you are arguing against something the submission doesn't say. If I were you I would reread it carefully and without prejudice, because based on your comments here I believe that you would enjoy learning the concepts it's presenting.

Re: On the criteria to be used in decomposing systems into modules (1972) [pdf]

#26

I really thought there had been a previous submission with more comments, but maybe it was another Parnas paper. The only past submission with comments: https://news.ycombinator.com/item?id=8849468 - Jan 7, 2015 (5 comments)

A Rational Design Process: How and Why to Fake It https://news.ycombinator.com/item?id=11101358 From Feb 2016, with just 2 comments. The paper is much better than the comments would suggest.

Maybe we need a Parnas day/week here on HN. A lot of his papers have shown up here, but seem to be light on comments in a lot of cases.

Re: On the criteria to be used in decomposing systems into modules (1972) [pdf]

#27
post #22
post #17

Earlier quoted context omitted.

I don't remember seeing a criticism of OOP that is a criticism of encapsulation. Everybody tends to agree that encapsulation is desirable. It seems to me criticisms of OOP are that it rolls too many things into one construct, the class: it's a type, with encapsulation of methods and data structure, plus inheritance, all into one. And it can lead to not so efficient data placement on modern CPU (AoS vs SoA). Languages…

I think Clojure quite explicitly rejects "encapsulationism". As does the "data on the outside" philosophy of event driven systems.

Many times one wants to encapsulate is to protect. Data is immutable in Clojure, which goes away with problems arising from everything accessible in wild west.

Re: On the criteria to be used in decomposing systems into modules (1972) [pdf]

#28
post #17
post #14

I always bring up this paper when I read a post criticizing OOP. It's a bit old but still very relevant and practical. In it the concept of information hiding, closely related to encapsulation, was first described. This concept plays a central role in the strategy for effective system modularization and is IMHO the basis of OOP. Shameless plug: A couple of years ago I wrote a post about this paper trying to expand it…

I don't remember seeing a criticism of OOP that is a criticism of encapsulation. Everybody tends to agree that encapsulation is desirable. It seems to me criticisms of OOP are that it rolls too many things into one construct, the class: it's a type, with encapsulation of methods and data structure, plus inheritance, all into one. And it can lead to not so efficient data placement on modern CPU (AoS vs SoA). Languages…

This is notably something haskell has largely been worse at than other languages in the ML family (only recently adding the backpack module system, which appears to be much less capable than the module systems in extended versions of SML and OCaml and is still not supported by tools like stack if I understand it right).

Haskell has modules, but until recently it had no module interfaces, so you could not write your code to depend on an abstract type and associated function definitions that could be swapped out dynamically (for ex: w/ mocks in testing).

Type classes are a related concept (i.e. an abstract definition of functions that may be implemented for a given type), but they enforce additional restrictions like coherency (i.e. only a single instance of class may be implemented for a given type). While this is advantageous in many situations, it's a huge pain in the ass when you need to do something like just mock network IO somewhere (as every combination of things you want to change out is going to need a newtype wrapper + class instances for all effects).

The preferred techniques for handling this the last time I used it were:

1. Transformer classes (usually w/ the "mtl" library + your own custom ones). Basically you could categorize types of useful effects into classes, use those class constraints in your function definitions + push any concrete implementations as high up the stack as possible, and use different monad transformer stacks to swap out the implementations of those effects. There's no getting around the single instance restriction of classes, but this allows you to only change out one "layer" of effects in code (say you have a transformer for network IO, you could change out only that concrete type), which reduces some of the labor involved. But there are subtle implications about the way transformers stack that change the meaning of your code, and the use of functional dependencies in MTL means you can only really use one instance of a class in your stack, so for using MTL to do something like things supply your functions w/ context/config values via MonadReader, you end up needing to smuggle around some unholy god object of everything you'd ever want to inject. Enjoy trying to write legible test cases w/ that.

2. Roll your own classes. This bypasses a lot of the weirdness you run into w/ transformer stacks, but its frankly a pain having to break out every possible effect you'll make use of into classes + defining instances for different use cases. And then you'll run into the reality that many libraries are making use of MTL-style classes so you can't entirely avoid them anyways (though you usually won't need to use MTL class constraints in your own code, and thus sidestep the aforementioned god objects).

3. Free monads. Basically describe your program as functions that don't actually run effects, but instead produce data structures describing a program that can be interpreted in several ways where the effects actually occur. This sounds awful but it's very easy to reason about as you have full control over the evaluation of effects in your interpreter functions, has a lot of nice advantages for testing + debugging as everything that could possibly cause a side effect is now inspectable as data, and is usually the least laborious of all solutions in my experience? This is known to be suboptimal from a performance perspective though.

All that said, backpack seems like it will be an improvement upon all these options, despite not having the full flexibility you get from first-class modules in other languages in the ML family tree.

One other note: 1ML looks like a very cool as a refinement of SML modules [1]. I have no real expertise w/ the design of programming languages to know if there are other problems with this approach, but I'd love to see a production-ready implementation.

[1]: https://people.mpi-sws.org/~rossberg/1ml/1ml-extended.pdf

Re: On the criteria to be used in decomposing systems into modules (1972) [pdf]

#29
post #25
post #23

Earlier quoted context omitted.

My experience is that anticipating future requirement changes do not work in general. So do not reflect in the design including the design of module boundaries the current assumptions about the future. Focus instead on other criteria, like reducing complexity or making the design more transparent.

I think I get what you're saying and there's merit to it. However, it appears to me that you are arguing against something the submission doesn't say. If I were you I would reread it carefully and without prejudice, because based on your comments here I believe that you would enjoy learning the concepts it's presenting.

I did read the article. My reply was about its conclusion. The article itself advocated a toolbox approach of creating useful tools first that could be written and tested independently and then assembling the application from those. But this has little to do with anticipating future changes, more about of flexibility of assembling the application itself. I.e. the conclusion was not warranted.

Re: On the criteria to be used in decomposing systems into modules (1972) [pdf]

#30
post #14

I always bring up this paper when I read a post criticizing OOP. It's a bit old but still very relevant and practical. In it the concept of information hiding, closely related to encapsulation, was first described. This concept plays a central role in the strategy for effective system modularization and is IMHO the basis of OOP. Shameless plug: A couple of years ago I wrote a post about this paper trying to expand it…

No post body was provided.
Post reply on HN