问:
Explicitly fill in requirements.txt for our Python projects?
As a user of pip install package and then pip freeze > requirements.txt, I was surprised to see a requirements.txt like this:

```<code># Flask
# License: BSD
# Upstream url: http://github.com/mitsuhiko/flask/
# Use: For API.
Flask==0.10.1

# Flask Scripting support for Flask
# License: BSD
# Upstream url: http://github.com/techniq/flask-script
# Use: For CLI scripts.
Flask-Script==2.0.5
</code>```

They have taken care to specify packages they need in specific versions. In contrast, (my usage of) pip freeze will bloat the file with dependencies as well, and versions may not be tightly controlled.

Is there a good reason to explicitly fill in requirements file instead? I can think of:

easier to remove packages when obsoleted, hence fill in requirements "by hand"

at scale, subtle bugs in API-compatible later versions can cause trouble, hence the version freeze

答:
To overcome the complexity of requirements.txt you could use VirtualEnv. It isolates project dependencies from the rest of the system. As a side effect pip freeze will only print out dependencies that are relevant to your project.

But in general, you use pip freeze only once and then maintain requirements.txt manually.


问:
In TDD should I have to write Test first or Interface first?
I am learning TDD using c#, as far as I know test should drive the development, that is first write a failing test after write the bare minimum code to pass the test then do refactoring.

But it is also said that "Program to Interface, not Implementation", so write an interface first. This is where my confusion starts, If I am writing Interface first then it is violating two things

The code that is written for interface is not driven by test.

It is not the bare minimum obviously i can write it with a simple class.

Should I start by writing tests for interface also ? without any implementation what am I going to test ?

If this question sounds silly sorry for that, but I am utterly confused. May be I am taking things too literally.

答:
What are we doing when we write an interface? Are we writing code, or are we designing?

I'm not a fan of the notion of Test Driven Design, but I love Test Driven Development. Personally, I've gotten my best results when I design the class up front by designing the interface before I write a test. I don't count the interface as code. The interface is a design that I will be implementing using TDD. Its likely to change an evolve as I work, but it is my roadmap (along with my test list).

I'll stop before I start to rant, but hopefully that's a helpful way for you to think about it.

ContentLicense: CC BY-SA 3.0


问:
When rewriting medium to large applications, which of these approaches are useful?
Despite Joel's missive that software rewrites are to be avoided under pain of death, it is still fairly common place. A lot of the existing software is good, but here and there, parts of it niggle, so for a while, you continue along your way.

"You can't polish a turd, but you can roll it in glitter"

So you tweak it here and there in a haphazard fashion - tinkering round the edges because you don't want to dig into the innards. Time passes, technical debt, software entropy - you get the picture.

This, until someone suited and booted says: "No more". Perhaps the language has fallen out of vogue, or has been superseeded. Now, which of the following (or mix of) can be used to aid the process? Are there any other methods? What other factors are there?

EDIT: I'm not looking for an ever increasing pick-and-mix list of approaches here - more a cohesive toolkit.

Line by line

If the project isn't too large, you may be able to look at the code line by line to get a feel for what it is doing.

Functional clone (dev view)

As a developer of the previous incarnation, you may have a spin on what the various functions are so you design from there.

Functional clone (user view)

The user (or team of), get together and decide which features are the most important and which can be parked until a later phase or scrapped.

Forensics

3rd party tools are used to extract the module names, method names and data structures.

Path analysis

Code is added (or perhaps existing audit code leveraged) to see which are the most commonly used parts of the program and go from there.

答:
Development techniques change and improve all the time, so if you are undertaking a rewrite, it's unlikely that you'll want to simply copy the current code's structure. So I'd suggest you can rule out the Functional clone (dev view), Forensics and Path analysis approaches. These will likely lead to duplication of bad parts of the code, as well as the good.

The other two approaches need to be used in conjunction with each other:

Functional clone (user view)
You are having to start from scratch, so by talking to the users up front, you can both:

Take the opportunity to find out if all the features in the current app really are required, and whether there's any missing features that they've always wanted.

Prioritise the order in which the features will be added and define a Minimum Viable Product, which will form the first release.

Line by line
Whilst it's time consuming, examining what the current app does is useful. It helps with requirements capture, as users may be unaware of the fact that behind-the-scenes features exist, or forget that vital piece of functionality that they only use at year-end, for example. This analysis should only be used for requirements capture though, unless some of the code can be re-used in the new version. Avoid line-by-line copying of functionality, especially if switching languages. This leads to non-idiomatic, hard yo maintain, code.

Polishing turds

A, somewhat off-topic (though you mentioned it), closing point, is that the statement, "you can't polish a turd", is untrue. Simply search for "polished coprolite" for examples of such polished fossilised faeces...


问:
Are header-only libraries more efficient?
Assumptions

One of the advantages of header-only libraries for C++ is that they do not need to be compiled separately.

In C and C++ inline makes sense only if the function is defined in a header file*.

Traditionally, in C, .c/.h layout has been used, where the header represents the minimal public interface of the translation unit. Similarly, .cpp/hpp.

Question

Are header-only libraries generally more efficient code- and execution time wise than the traditional layout? If so, is this because of extensive inlining or other optimizations?

* - defining the function in a header allows the compiler to see the implementation during compilation of any translation unit and practically makes inlining code possible

答:
Well, let's first demolish some of your assumptions:

One of the advantages of header-only libraries for C++ is that they do not need to be compiled separately.

Compiling things separately means potentially not having to recompile everything if only a part changes.

So, a disadvantage instead of an advantage.

In C and C++ inline makes sense only if the function is defined in a header file*.

Yes, the only effect inline has left is the exception to the one-definition-rule.

Woe unto you if those definitions are different in any way though.

So, if a function is internal to a compilation-unit, mark it static. That also makes inlining more likely, as the function needs to be available in order to inline it.

Still, take a look at link-time-optimization, as supported by at least MSVC++, gcc and clang.

Traditionally, in C, .c/.h layout has been used, where the header represents the minimal public interface of the translation unit. Similarly, .cpp/hpp.

Well, only presenting the minimal interface is certainly one of the goals, to achieve higher API and ABI stability, and to minimize compilation times.

Especially C++ classes aren't really geared to that though, as all the private bits leak into the header, as do the protected ones whether you want to derive from it or not.

The design-pattern PIMPL is for reducing such details.

The part where separating interface and implementation completely fails in C++ is templates though.

The committee tried to do something with exported templates, but that has been abandoned as too complicated and not really working.

Now, they are working on a proper module system, though it's slow going. That severely reduce compile-times, and should also increase API and ABI stability by decreasing their surface.

Are header-only libraries generally more efficient code- and execution time wise than the traditional layout? If so, is this because of extensive inlining or other optimizations?

Header-only libraries can be more efficient in code-size and execution-time, though that depends on whether the library is shared, how much of it is used, in what ways, and whether inlining proves a decisive win in that specific case.

And the reason inlining is so important for optimization isn't because inlining itself is such a great boost, but due to the opportunities for constant-propagation and further optimization it opens.


问:
What is the alternative design pattern of a state machine that may have recursive state change?
I have a state machine like code, which has state A,B and C, with a function changeState(char i) which can change the state of a system, and each state can also call changeState(char i) to switch the system to another state:

```<code>struct State{
    State(char aName){
        this->name=aName;
    }
    char name;
};

void changeState(char i);

struct A : public State{
    A():State('A'){
        changeState('B');
    }
};

struct B : public State{
    B():State('B'){
    changeState('C');
    }
};

struct C : public State{
    C():State('C'){
    }
};

State* state;
void changeState(char i){
    switch(i){
        case 'A':
            state=new A();
            break;
        case 'B':
            state=new B();
            break;
        case 'C':
            state=new C();
            break;
    }
}
</code>```

Now this code has at least 2 problems:

if I do not set the state as global, I need to handle the memory management of each states, which increases the complexity of the code

if recursive state change occurs, the final state is not as I expected:

Suppose I want to trigger state change, start from A to C (to simplify the code now the state change occurs in constructor only, but in real code it is in other method which calls after constructor):

```<code>int main(){
    changeState('A');
    printf("%c\n",state->name);
    return 0;
}
</code>```

the flow is : changeState('A')->new A()->changeState('B')->new B()->changeState(C)->new C(), I want the last state be C, but now is A.

My question is, what is the alternative software architecture or design pattern if my state machine may change state recursively? or, if possible, how to modify current code to overcome the problem?

答:
First of all, I'd always avoid global state unless it is absolutely necessary. It makes extended your code hard, testing your code hard, and debugging your code hard. For the expense of having a state machine object that is passed to each state when it's created? Definitely not.

But I don't think it's necessary anyway. Your code has another antipattern that you haven't highlighted: your State objects cause side-effects in their constructors, which is a seriously bad idea. I'd fix both problems with a single change: have a class StateMachine with a method:

```<code>void changeState(State * requested)
{
    State * alternative;
    while (alternative = requested-> getAlternative ())
        requested = alternative;
    currentState = requested;
}
</code>```

Where getAlternative is a virtual method in State that returns null, and can be overridden by each subclass to return a different state if necessary.

Once this is done, you can allocate a single instance of each State subclass and use those rather than calling "new" all the time, which will save the possibility of memory leaks (which look like they could have been a problem in your design).

Body:
First of all, I'd always avoid global state unless it is absolutely necessary. It makes extended your code hard, testing your code hard, and debugging your code hard. For the expense of having a state machine object that is passed to each state when it's created? Definitely not.

But I don't think it's necessary anyway. Your code has another antipattern that you haven't highlighted: your State objects cause side-effects in their constructors, which is a seriously bad idea. I'd fix both problems with a single change: have a class StateMachine with a method:

void changeState(State * requested)
{
    State * alternative;
    while (alternative = requested-> getAlternative ())
        requested = alternative;
    currentState = requested;
}

Where getAlternative is a virtual method in State that returns null, and can be overridden by each subclass to return a different state if necessary.

Once this is done, you can allocate a single instance of each State subclass and use those rather than calling "new" all the time, which will save the possibility of memory leaks (which look like they could have been a problem in your design).


问:
Should one derive / inherit from std::exception?
While designing my first 'serious' C++ library, I'm asking myself:

Is it good style to derive ones exceptions from std::exception and it's offsprings?!

Even after reading

Designing exception classes

What is a 'good number' of exceptions to implement for my library?

I'm still not sure. Because, besides common (but maybe not good) practice, I would assume, as a library user, that a library function would throw std::exceptions only when standard library functions failed in the library implementation, and it can't do anything about it. But still, when writing application code, for me it's very convenient, and also IMHO good looking to just throw a std::runtime_error. Also my users also can rely on the defined minimum interface, like what() or codes.

And for example, my user supplies faulty arguments, what would be more convenient, than to throw a std::invalid_argument, wouldn't it?
So combined with the yet common use of std::exception I see in others code:
Why not go even further and derive from your custom exception class (e.g. lib_foo_exception) and also from std::exception.

Thoughts?

答:
All exceptions should inherit from std::exception.

Suppose, for example, I need to call ComplexOperationThatCouldFailABunchOfWays(), and I want to handle any exceptions that it could throw.  If everything inherits from std::exception, this is easy.  I only need a single catch block, and I have a standard interface (what()) for getting details.

```<code>try {
    ComplexOperationThatCouldFailABunchOfWays();
} catch (std::exception& e) {
    cerr << e.what() << endl;
}
</code>```

If exceptions do NOT inherit from std::exception, this gets much uglier:

```<code>try {
    ComplexOperationThatCouldFailABunchOfWays();
} catch (std::exception& e) {
    cerr << e.what() << endl;
} catch (Exception& e) {
    cerr << e.Message << endl;
} catch (framework_exception& e) {
    cerr << e.Details() << endl;
}
</code>```

Regarding whether to throw runtime_error or invalid_argument versus creating your own std::exception subclasses to throw: My rule of thumb is to introduce a new subclass whenever I need to handle a particular type of error differently than other errors (i.e., whenever I need a separate catch block).

If I introduce a new exception subclass for every conceivable type of error, even if I don't need to handle them separately, then that adds a lot of class proliferation.

If I reuse existing subclasses to mean something specific (i.e., if a runtime_error thrown here means something different than a generic runtime error), then I run the risk of conflicting with other uses of the existing subclass.

If I don't need to handle an error specifically, and if the error that I'm throwing exactly matches one of the existing standard library's errors (such as invalid_argument), then I reuse the existing class. I just don't see much benefit to adding a new class in this case. (The C++ Core Guidelines disagree with me here - they recommend always using your own classes.)

The C++ Core Guidelines have further discussion and examples.

Body:
All exceptions should inherit from std::exception.

Suppose, for example, I need to call ComplexOperationThatCouldFailABunchOfWays(), and I want to handle any exceptions that it could throw.  If everything inherits from std::exception, this is easy.  I only need a single catch block, and I have a standard interface (what()) for getting details.

try {
    ComplexOperationThatCouldFailABunchOfWays();
} catch (std::exception& e) {
    cerr << e.what() << endl;
}

If exceptions do NOT inherit from std::exception, this gets much uglier:

try {
    ComplexOperationThatCouldFailABunchOfWays();
} catch (std::exception& e) {
    cerr << e.what() << endl;
} catch (Exception& e) {
    cerr << e.Message << endl;
} catch (framework_exception& e) {
    cerr << e.Details() << endl;
}

Regarding whether to throw runtime_error or invalid_argument versus creating your own std::exception subclasses to throw: My rule of thumb is to introduce a new subclass whenever I need to handle a particular type of error differently than other errors (i.e., whenever I need a separate catch block).

If I introduce a new exception subclass for every conceivable type of error, even if I don't need to handle them separately, then that adds a lot of class proliferation.

If I reuse existing subclasses to mean something specific (i.e., if a runtime_error thrown here means something different than a generic runtime error), then I run the risk of conflicting with other uses of the existing subclass.

If I don't need to handle an error specifically, and if the error that I'm throwing exactly matches one of the existing standard library's errors (such as invalid_argument), then I reuse the existing class. I just don't see much benefit to adding a new class in this case. (The C++ Core Guidelines disagree with me here - they recommend always using your own classes.)

The C++ Core Guidelines have further discussion and examples.


答:
I would assume, as a library user, that a library function would throw std::exceptions only when standard library functions failed in the library implementation, and it can't do anything about it

That is an incorrect assumption.

The standard exception types are provided for "commoner" use. They are not designed to only be used by the standard library.

Yes, make everything ultimately inherit from std::exception. Oftentimes, that'll involve inheriting from std::runtime_error or std::logic_error. Whatever is appropriate for the class of exception you're implementing.

This is of course subjective — several popular libraries completely ignore the standard exception types, presumably to decouple the libraries from the standard library. Personally I think this is extremely selfish! It makes catching exceptions that much more difficult to get right.

Speaking personally, I often just throw a std::runtime_error and be done with it. But that's getting into a discussion about how granular to make your exception classes, which is not what you're asking.

Title: Should one derive / inherit from std::exception?

Body:
While designing my first 'serious' C++ library, I'm asking myself:

Is it good style to derive ones exceptions from std::exception and it's offsprings?!

Even after reading

Designing exception classes

What is a 'good number' of exceptions to implement for my library?

I'm still not sure. Because, besides common (but maybe not good) practice, I would assume, as a library user, that a library function would throw std::exceptions only when standard library functions failed in the library implementation, and it can't do anything about it. But still, when writing application code, for me it's very convenient, and also IMHO good looking to just throw a std::runtime_error. Also my users also can rely on the defined minimum interface, like what() or codes.

And for example, my user supplies faulty arguments, what would be more convenient, than to throw a std::invalid_argument, wouldn't it?
So combined with the yet common use of std::exception I see in others code:
Why not go even further and derive from your custom exception class (e.g. lib_foo_exception) and also from std::exception.

Thoughts?


答:
A rewrite has to offer value to the users. That's a must. If you simply declare that an app is too hard to maintain, there's too much technical debt, et cetera, your sponsors will look at you and ask, "Well who made it that way?" And that's a good question. Why write a check to the same team who screwed it up last time? What's different?

That's where a shift in your thinking might come in handy. It's not simply a rewrite; it's Badass App Version X!

There is no view other than the user view.

And it's not a functional clone. It can't be. It has to be better than that. All the nuisances -- extra clicks, clunky navigation, ugly UI, waiting -- you have to fix them. All the feature requests that would have compromised the original app's design -- you have to demonstrate you understand the users' goals so well that those features integrate perfectly into your new design. That, or demonstrate you now know so much that you understand clearly there is no alternative reality in the multiverse where feature Y could exist in Badass App Version X.

Regarding Functional clone (dev view) and Forensics, do yourself a favor and reconsider absolutely every name and relationship. Build improved models based on what you've learned. Don't copy anything until it's been vetted by your extremely thoughtful and deep-thinking team.

Finally, we haven't nailed down what "medium-large" application means. I'm guessing there are opportunities for incremental redesign versus the big bang approach. Are there services? If so, maybe this is a good time to entertain a microservice approach. Build your first microservice using your new technology. While you're at it, pull that business logic out of the UI where the new service is consumed!

Is the UI delivered in the browser? If so, you can do all sorts of interesting things with subdomains, proxies, and virtual directories to allow you to rewrite portions of the UI in a new technology. Sure, it's tricky. You can't have User Admin looking all Bootstrappy while Mail Merge is a gunmetal grey enterprise nightmare. Your UX person may have to bite their tongue until the conversion is complete.

Interested in new data technology? Identify some small portion of the data model that would work well in MongoDB or Stardog or Big Table.

Layer in distributed caching.

You get the idea.

The advantages to this approach are legion:

You can verify your assumptions about a rewrite were correct. If it's still a mess, maybe call it off before you spend all your company's money.

Demonstrate concrete progress to your sponsors.

Distribute risk across time versus saving it all for one terrifying rollout.

Learn as you go. It's easier to adjust for the next piece of development versus doing yet another rewrite.

Breaking off chunks forces you to think about modular design.

Title: When rewriting medium to large applications, which of these approaches are useful?

Body:
Despite Joel's missive that software rewrites are to be avoided under pain of death, it is still fairly common place. A lot of the existing software is good, but here and there, parts of it niggle, so for a while, you continue along your way.

"You can't polish a turd, but you can roll it in glitter"

So you tweak it here and there in a haphazard fashion - tinkering round the edges because you don't want to dig into the innards. Time passes, technical debt, software entropy - you get the picture.

This, until someone suited and booted says: "No more". Perhaps the language has fallen out of vogue, or has been superseeded. Now, which of the following (or mix of) can be used to aid the process? Are there any other methods? What other factors are there?

EDIT: I'm not looking for an ever increasing pick-and-mix list of approaches here - more a cohesive toolkit.

Line by line

If the project isn't too large, you may be able to look at the code line by line to get a feel for what it is doing.

Functional clone (dev view)

As a developer of the previous incarnation, you may have a spin on what the various functions are so you design from there.

Functional clone (user view)

The user (or team of), get together and decide which features are the most important and which can be parked until a later phase or scrapped.

Forensics

3rd party tools are used to extract the module names, method names and data structures.

Path analysis

Code is added (or perhaps existing audit code leveraged) to see which are the most commonly used parts of the program and go from there.


问:
Is it bad to refer to access array elements via pointer arithmetic instead of the [] operator?
I've just started learning to program in C, and to improve my understanding of pointers and arrays, I tried to refer to the elements of an array without creating any pointer at all:

```<code>for(k1 = 0; k1 < ROW; k1++){
    for(k2 = 0; k2 < COLUMN; k2++){

        array[k1][k2] = k1*COLUMN + k2 + 1;

        printf("[%d][%d] = %d\n", k1, k2, *(array[k1] + k2));

    }
}
</code>```

The entire code compiles and runs flawlessly.

I imagine having to create a pointer for every single array in a big source code seems to be highly inefficient.

So, rather than having the address of an array stored and retrieved by using a pointer, is it a bad programming practice to use the address of the array directly, as shown above?

答:
Yes, it's bad practice, but not for inefficiency reasons.

Array operator uses pointer arithmetric under the hood, so they're equally efficient.

Problem with pointer arithmetric is that it's very error prone and harder to read.

Rule of thumb: Don't use pointer arithmetric unless you have to.


答:
It's "bad" only to the extent that's less readable. a[x] is the same thing as *(a+x), so there's no difference in efficiency or behavior (in fact, x[a] will also work). It's just that a[x] is usually a lot more intuitive to us humans.

But that's not to say readability isn't a big deal. To see how big, think about how you would "read" these two expressions if you saw them in code:

*(a+x) = "The thingy pointed to by the sum of pointer a and integer x"

a[x] = "The xth member of array a"

Similarly, when you need to refer to the address of an array element:

(a+x) = "The sum of pointer a and integer x"

&a[x] = "The address of the xth member of array a"

Most of the time, the [] versions are just easier to understand when you're looking at non-trivial code operating on several different arrays (especially arrays of arrays). That's why the [] operator exists in the first place.

P.S. Doing this sort of thing strictly as a learning exercise is a very good idea. It's important to understand that arrays really are just pointers and offsets.

Title: Is it bad to refer to access array elements via pointer arithmetic instead of the [] operator?

Body:
I've just started learning to program in C, and to improve my understanding of pointers and arrays, I tried to refer to the elements of an array without creating any pointer at all:

```<code>for(k1 = 0; k1 < ROW; k1++){
    for(k2 = 0; k2 < COLUMN; k2++){

        array[k1][k2] = k1*COLUMN + k2 + 1;

        printf("[%d][%d] = %d\n", k1, k2, *(array[k1] + k2));

    }
}
</code>```

The entire code compiles and runs flawlessly.

I imagine having to create a pointer for every single array in a big source code seems to be highly inefficient.

So, rather than having the address of an array stored and retrieved by using a pointer, is it a bad programming practice to use the address of the array directly, as shown above?


问:
Exceptions - "what happened" vs "what to do"
We use exceptions to let the consumer of the code handle unexpected behaviour in a useful way.  Usually exceptions are built around "what happened" scenario - like FileNotFound (we were unable to find file you specified) or ZeroDivisionError (we can divide by 0).

What if there is a need to specify the expected behaviour of the consumer?

For example, imagine we have fetch resource, which performs HTTP request and returns retrieved data.  And instead of errors like ServiceTemporaryUnavailable or RateLimitExceeded we would just raise a RetryableError suggesting that the consumer should just retry the request and forget about specific failure.  So, we are basically suggesting an action to the caller - the "what to do".

We do not do this often because we don't know all the consumers' usecases.  But imagine that in some specific component we do know the best course of actions for a caller - so should we then make use of "what to do" approach?

答:
But imagine that is some specific component we do know the best course of actions for a caller.

This almost always fails for at least one of your callers, for which this behaviour is incredibly irritating. Don't assume you know best. Tell your users what's happening, not what you assume they should do about it. In many cases it's already clear what a sane course of action should be (and, if it's not, make a suggestion in your user manual).

For example, even the exceptions given in your question demonstrate your broken assumption: a ServiceTemporaryUnavailable equates to "try again later", and RateLimitExceeded equates to "woah there chill out, maybe adjust your timer parameters, and try again in a few minutes". But the user may as well want to raise some sort of alarm on ServiceTemporaryUnavailable (which indicates a server problem), and not for RateLimitExceeded (which doesn't).

Give them the choice.

ContentLicense: CC BY-SA 4.0


答:
Warning! C++ programmer coming in here with possibly-different ideas
  of how exception-handling should be done trying to answer a question
  which is certainly about another language!

Given this idea:

For example, imagine we have fetch resource, which performs HTTP
  request and returns retrieved data. And instead of errors like
  ServiceTemporaryUnavailable or RateLimitExceeded we would just raise a
  RetryableError suggesting the consumer that it should just retry the
  request and do not care about specific failure.

... one thing I would suggest is that you might be mixing up concerns of reporting an error with courses of action to respond to it in a way that might degrade the generality of your code or require a lot of "translation points" for exceptions.

For example, if I model a transaction involving loading a file, it might fail for a number of reasons. Perhaps loading the file involves loading a plugin which does not exist on the user's machine. Perhaps the file is simply corrupt and we encountered an error in parsing it.

No matter what happens, let's say the course of action is to report what happened to the user and prompt him about what he wants to do about it ("retry, load another file, cancel").

Thrower vs. Catcher

That course of action applies regardless of what kind of error we encountered in this case. It's not embedded into the general idea of a parsing error, it's not embedded into the general idea of failing to load a plugin. It's embedded into the idea of encountering such errors during the precise context of loading a file (the combination of loading a file and failing). So typically I see it, crudely speaking, as the catcher's responsibility to determine the course of action in response to a thrown exception (ex: prompting the user with options), not the thrower's.

Put another way, the sites that throw exceptions typically lack this kind of contextual information, especially if the functions that throw are generally applicable. Even in a totally degeneralized context when they have this information, you end up cornering yourself in terms of recovery behavior by embedding it into the throw site. The sites that catch are the ones that generally have the most amount of information available to determine a course of action, and give you one central place to modify if that course of action should ever change for that given transaction.

When you start trying to throw exceptions no longer reporting what's wrong but trying to determine what to do, that might degrade the generality and flexibility of your code. A parsing error shouldn't always lead to this kind of prompt, it varies by the context in which such an exception is thrown (the transaction under which it was thrown).

The Blind Thrower

Just in general, a lot of the design of exception-handling often revolves around the idea of a blind thrower. It doesn't know how the exception is going to be caught, or where. The same applies for even older forms of error recovery using manual error propagation. Sites that encounter errors do not include a user course of action, they only embed the minimal information to report what kind of error was encountered.

Inverted Responsibilities and Generalizing the Catcher

On thinking about this more carefully, I was trying to imagine the kind of codebase where this might become a temptation. My imagination (possibly wrong) is that your team is still playing the role of the "consumer" here and implementing most of the calling code as well. Perhaps you have a lot of disparate transactions (a lot of try blocks) that can all run into the same sets of errors, and all should, from a design perspective, lead to a uniform course of recovery action.

Taking into account the wise advice from Lightness Races in Orbit's fine answer (which I think is really coming from an advanced library-oriented mindset), you might still be tempted to throw "what to do" exceptions, only closer to the transaction recovery site.

It might be possible to find an intermediary, common transaction-handling site out of this here which actually centralizes the "what to do" concerns but still within the context of catching.

This would only apply if you can design some kind of general function which all of these outer transactions use (ex: a function that inputs another function to call or an abstract transaction base class with overridable behavior modeling this intermediary transaction site that does the sophisticated catching).

Yet that one could be responsible for centralizing the user course of action in response to a variety of possible errors, and still within the context of catching rather than throwing. Simple example (Python-ish pseudocode, and I'm not an experienced Python developer in the slightest so there might be a more idiomatic way of going about this):

```<code>def general_catcher(task):
    try:
       task()
    except SomeError1:
       # do some uniformly-designed recovery stuff here
    except SomeError2:
       # do some other uniformly-designed recovery stuff here
    ...
</code>```

[Hopefully with a better name than general_catcher]. In this example, you can pass in a function containing what task to perform but still benefit from generalized/unified catch behavior for all the types of exceptions you're interested in, and continue to extend or modify the "what to do" part all you like from this central location and still within a catch context where this is typically encouraged. Best of all, we can keep the throwing sites from concerning themselves with "what to do" (preserving the notion of the "blind thrower").

If you find none of these suggestions here helpful and there's a strong temptation to throw "what to do" exceptions anyway, mainly be aware that this is very anti-idiomatic at the very least, as well as potentially discouraging a generalized mindset.

Title: Exceptions - "what happened" vs "what to do"

Body:
We use exceptions to let the consumer of the code handle unexpected behaviour in a useful way.  Usually exceptions are built around "what happened" scenario - like FileNotFound (we were unable to find file you specified) or ZeroDivisionError (we can divide by 0).

What if there is a need to specify the expected behaviour of the consumer?

For example, imagine we have fetch resource, which performs HTTP request and returns retrieved data.  And instead of errors like ServiceTemporaryUnavailable or RateLimitExceeded we would just raise a RetryableError suggesting that the consumer should just retry the request and forget about specific failure.  So, we are basically suggesting an action to the caller - the "what to do".

We do not do this often because we don't know all the consumers' usecases.  But imagine that in some specific component we do know the best course of actions for a caller - so should we then make use of "what to do" approach?

Body:
Warning! C++ programmer coming in here with possibly-different ideas
  of how exception-handling should be done trying to answer a question
  which is certainly about another language!

Given this idea:

For example, imagine we have fetch resource, which performs HTTP
  request and returns retrieved data. And instead of errors like
  ServiceTemporaryUnavailable or RateLimitExceeded we would just raise a
  RetryableError suggesting the consumer that it should just retry the
  request and do not care about specific failure.

... one thing I would suggest is that you might be mixing up concerns of reporting an error with courses of action to respond to it in a way that might degrade the generality of your code or require a lot of "translation points" for exceptions.

For example, if I model a transaction involving loading a file, it might fail for a number of reasons. Perhaps loading the file involves loading a plugin which does not exist on the user's machine. Perhaps the file is simply corrupt and we encountered an error in parsing it.

No matter what happens, let's say the course of action is to report what happened to the user and prompt him about what he wants to do about it ("retry, load another file, cancel").

Thrower vs. Catcher

That course of action applies regardless of what kind of error we encountered in this case. It's not embedded into the general idea of a parsing error, it's not embedded into the general idea of failing to load a plugin. It's embedded into the idea of encountering such errors during the precise context of loading a file (the combination of loading a file and failing). So typically I see it, crudely speaking, as the catcher's responsibility to determine the course of action in response to a thrown exception (ex: prompting the user with options), not the thrower's.

Put another way, the sites that throw exceptions typically lack this kind of contextual information, especially if the functions that throw are generally applicable. Even in a totally degeneralized context when they have this information, you end up cornering yourself in terms of recovery behavior by embedding it into the throw site. The sites that catch are the ones that generally have the most amount of information available to determine a course of action, and give you one central place to modify if that course of action should ever change for that given transaction.

When you start trying to throw exceptions no longer reporting what's wrong but trying to determine what to do, that might degrade the generality and flexibility of your code. A parsing error shouldn't always lead to this kind of prompt, it varies by the context in which such an exception is thrown (the transaction under which it was thrown).

The Blind Thrower

Just in general, a lot of the design of exception-handling often revolves around the idea of a blind thrower. It doesn't know how the exception is going to be caught, or where. The same applies for even older forms of error recovery using manual error propagation. Sites that encounter errors do not include a user course of action, they only embed the minimal information to report what kind of error was encountered.

Inverted Responsibilities and Generalizing the Catcher

On thinking about this more carefully, I was trying to imagine the kind of codebase where this might become a temptation. My imagination (possibly wrong) is that your team is still playing the role of the "consumer" here and implementing most of the calling code as well. Perhaps you have a lot of disparate transactions (a lot of try blocks) that can all run into the same sets of errors, and all should, from a design perspective, lead to a uniform course of recovery action.

Taking into account the wise advice from Lightness Races in Orbit's fine answer (which I think is really coming from an advanced library-oriented mindset), you might still be tempted to throw "what to do" exceptions, only closer to the transaction recovery site.

It might be possible to find an intermediary, common transaction-handling site out of this here which actually centralizes the "what to do" concerns but still within the context of catching.

This would only apply if you can design some kind of general function which all of these outer transactions use (ex: a function that inputs another function to call or an abstract transaction base class with overridable behavior modeling this intermediary transaction site that does the sophisticated catching).

Yet that one could be responsible for centralizing the user course of action in response to a variety of possible errors, and still within the context of catching rather than throwing. Simple example (Python-ish pseudocode, and I'm not an experienced Python developer in the slightest so there might be a more idiomatic way of going about this):

def general_catcher(task):
    try:
       task()
    except SomeError1:
       # do some uniformly-designed recovery stuff here
    except SomeError2:
       # do some other uniformly-designed recovery stuff here
    ...

[Hopefully with a better name than general_catcher]. In this example, you can pass in a function containing what task to perform but still benefit from generalized/unified catch behavior for all the types of exceptions you're interested in, and continue to extend or modify the "what to do" part all you like from this central location and still within a catch context where this is typically encouraged. Best of all, we can keep the throwing sites from concerning themselves with "what to do" (preserving the notion of the "blind thrower").

If you find none of these suggestions here helpful and there's a strong temptation to throw "what to do" exceptions anyway, mainly be aware that this is very anti-idiomatic at the very least, as well as potentially discouraging a generalized mindset.


答:
I think most of the time it would be better to pass arguments to the function telling it how to handle those situations.

For example, consider a function:

```<code>Response fetchUrl(URL url, RetryPolicy retryPolicy);
</code>```

I can pass RetryPolicy.noRetries() or RetryPolicy.retries(3) or whatever. In the case a of retryable failure, it will consult the policy to decide whether or not it should retry.

Body:
I think most of the time it would be better to pass arguments to the function telling it how to handle those situations.

For example, consider a function:

Response fetchUrl(URL url, RetryPolicy retryPolicy);

I can pass RetryPolicy.noRetries() or RetryPolicy.retries(3) or whatever. In the case a of retryable failure, it will consult the policy to decide whether or not it should retry.


问:
Using self.method vs the scope :method DSL
According to the Thoughbot Rails Style Guide, we should

Use def self.method, not the scope :method DSL.

My question is: is this simply for the sake of choosing one of these styles and sticking with it for consistency, or is there another reason I'm missing?

Regardless of whether or not you would adhere to this style guide, I was just curious.

答:
This is a great article discussing the difference:

http://blog.plataformatec.com.br/2013/02/active-record-scopes-vs-class-methods/

TLDR:

Scopes are always chainable.

Scopes always return a relation.

Scopes look a bit cleaner when you extend them.


问:
How to manage microservices?
We are trying to adopt the microservice approach to our newly developed application.

However, we found that there are too many repos, branches, and releases need to be managed. Originally, we only have 2~4 repos to manage for an application. After adopting the microservice approach, we may have 10~20 repos for an application with the same complexity.

So, are there any best practices on how to manage these microservices of a large application?

答:
Standardization, Automation and Virtualization.

Initially with the first few microservices it's not too bad.  Different developers have their machines configured differently which presents some challenges but usually these can be quickly addressed.  But once you get past 3 or 4 services things get tricky.  Small differences in environments become a constant pain.  Making sure everyone has the same environment without much work and managing the flow of code becomes very burdensome as you are seeing / have found.

The approaches I have seen to help address this are:

Standardization

Define the set of services.  Define how they run.  Define what ports things run on.  Define some standards and make sure they are followed.  Use virtualization (below) to implement these standards universally without effort.

Automation

You want 1-step (or as few steps as possible) to create and update environment procedures.  There may be 100 actual steps but you want to reduce that to as few as possible so that updating your environment with the constant flow of changes is very easy.  You want to avoid even needing procedures and following detailed steps.  You should be able to update and get things running in less than 5 minutes and ideally less than 1 minute.

Virtualization

With this, for example Vagrant, you can make sure that, unlike the local individual developers environment (which may be highly customzied) virtual machines (for development) give the opportunity to have EXACTLY the same environment, same settings, profiles, dot files, etc. separate from developers personal environments.

Using the above will not necessarily reduce the amount of repos, branches, releases.  However it will help make it easy to do and not burdensome.  One thing that I am seeing with the organizations I have seen take on this challenge is that this is a new area that takes time and effort to get right.  You may need to dedicate specific resources to get it right and keep it maintained.

For actual releases you will need to put more effort into defining how things work so that the pattern can be repeated.  You will need to spend more time and effort to get this right when compared to a 1 repo release setup.  The idea generally though is that with smaller repos and smaller changes, if you have a repeatable deployment process, it will be easier to deploy individual pieces.  Automation of the processes is also key here.

Title: How to manage microservices?


问:
How to represent a collection with capacity in a database?
Concerning normalization of a one to many relationship, I am not sure how to represent a collection with a specified capacity in a database.  I can think of two ways to represent an entity A with a one-to-many relationship with B:

When Table A is created with n capacity, insert n rows into Table B.  The amount of rows in Table B represents the capacity for that collection (Like allocating memory).  These rows must be updated as elements are placed and removed from the collection.

When Table A is created with n capacity, represent the capacity as a column in A.  Rows must be inserted and deleted from Table B as elements are placed and removed from the collection.  The application ensures that table B has no more than n rows.

What are the benefits or detriments of each of these ways?  Is there a standard method for doing this?  Are there performance or maintenance concerns?

答:
For at least two reasons, option #2 is the winner to me (although not sure if this is considered "standard" reasoning):

With option 1, you will have wasted/empty/null rows that are added by default every time an instance of the parent entity is created. Not only does this potentially waste resources, but you'll probably have frequent times where query results have to be pruned to account for this, and could make any stored procedure code uglier.

Logically, it's not really the DB's responsibility to enforce the capacity constraint. As long as the parent entity records the capacity, your model is complete. It's then up to the app, as you note, to ensure that the model's requirements are enforced.


答:
What are the benefits or detriments of each of these ways?

Option 1 Benefits

Can be enforced at the database level by granting users update privileges on B but no insert or delete privilege. Obviously a privileged user (maybe a stored procedure) should create the initial rows.

The capacity, being an attribute of A is a column of A, which makes sense.

Option 1 disadvantages

None that I know of.

Option 2 Benefits

The capacity, being an attribute of A is a column of A, which makes sense.

Option 2 disadvantages

The application (or applications) must enforce a business rule that could be easily enforced at the database level.

Recommendation:

A combination of both:

Store the capacity of A as a column of A.

A privilege user (the backend) will create as many rows in B as A's capacity.

Normal users can't insert or delete from B, just update.

When a change is made to A's capacity, the backend inserts or delete rows so the number of rows match A's capacity.

Is there a standard method for doing this?

Frankly, I don't think so.

Are there performance or maintenance concerns?

Option 2 can create inconsistencies due to programming errors.

Note:

There's no such thing as "the application". The one-app<->one-DB rule doesn't apply nowadays when you will potentially have several front-ends to the same backend.

Possibility of adding a trigger to enforce option 2:

In don't know what your RDBMS is but this is a pseudo code:

```<code>create trigger mytrigger before insert on table B for each row
declare
  var c integer;
  var ca integer;
begin
     select count(*) into c from B where id_a = :new.id_a;
     select capacity into ca from A where id = :new.id_a;
     if c > ca then
          RAISE_APPLICATION_ERROR(-20001, 'Cannot Insert mora than '||ca||' rows in this table');
     enf if;
end
</code>```

Title: How to represent a collection with capacity in a database?

Body:
Concerning normalization of a one to many relationship, I am not sure how to represent a collection with a specified capacity in a database.  I can think of two ways to represent an entity A with a one-to-many relationship with B:

When Table A is created with n capacity, insert n rows into Table B.  The amount of rows in Table B represents the capacity for that collection (Like allocating memory).  These rows must be updated as elements are placed and removed from the collection.

When Table A is created with n capacity, represent the capacity as a column in A.  Rows must be inserted and deleted from Table B as elements are placed and removed from the collection.  The application ensures that table B has no more than n rows.

What are the benefits or detriments of each of these ways?  Is there a standard method for doing this?  Are there performance or maintenance concerns?

Body:
What are the benefits or detriments of each of these ways?

Option 1 Benefits

Can be enforced at the database level by granting users update privileges on B but no insert or delete privilege. Obviously a privileged user (maybe a stored procedure) should create the initial rows.

The capacity, being an attribute of A is a column of A, which makes sense.

Option 1 disadvantages

None that I know of.

Option 2 Benefits

The capacity, being an attribute of A is a column of A, which makes sense.

Option 2 disadvantages

The application (or applications) must enforce a business rule that could be easily enforced at the database level.

Recommendation:

A combination of both:

Store the capacity of A as a column of A.

A privilege user (the backend) will create as many rows in B as A's capacity.

Normal users can't insert or delete from B, just update.

When a change is made to A's capacity, the backend inserts or delete rows so the number of rows match A's capacity.

Is there a standard method for doing this?

Frankly, I don't think so.

Are there performance or maintenance concerns?

Option 2 can create inconsistencies due to programming errors.

Note:

There's no such thing as "the application". The one-app<->one-DB rule doesn't apply nowadays when you will potentially have several front-ends to the same backend.

Possibility of adding a trigger to enforce option 2:

In don't know what your RDBMS is but this is a pseudo code:

create trigger mytrigger before insert on table B for each row
declare
  var c integer;
  var ca integer;
begin
     select count(*) into c from B where id_a = :new.id_a;
     select capacity into ca from A where id = :new.id_a;
     if c > ca then
          RAISE_APPLICATION_ERROR(-20001, 'Cannot Insert mora than '||ca||' rows in this table');
     enf if;
end


问:
What is the difference between Adapter and Delegation design pattern?
I am very confused about Adapter and Delegation design pattern. In Adapter pattern we bring an intermediate class to interact with another class. And in Delegation pattern we also bring an intermediate class to refer/interact with another class. </p>

答:
Structurally the two patterns are similar. But remember that design patterns are meant to be solutions to specific problems. The problems that Adapter and Delegation solve are quite different.

A typical problem for Delegation is when you go to implement a class, and realize that part of the implementation is quite complicated, and having a helper object to encapsulate a particular chunk of the implementation logic would make things significantly more readable.

A typical problem for Adapter is when you have two classes that do the same thing, but with different interfaces, yet you want your code to be able to work with both. So you decide which interface is better for your purposes, then write an adapter around the other class so that you can use it as if it had the better interface all along.


问:
Swift functions vs computed properties
Say I have have a class Event as follows:

```<code>class Event {
    private var attendees: [Person] = []

    // Case 1
    //*******
    // Should I use a func…
    func countOfAttendees() -> Int {
        return attendees.count
    }

    // …or a var
    var countOfAttendees: Int {
        return attendees.count
    }

    // Case 2
    //*******
    // Should I use a func…
    func countOfPaidAttendees() -> Int {
        return attendees.filter({$0.hasPaid}).count
    }

    // …or a var
    var countOfPaidAttendees: Int {
        return attendees.filter({$0.hasPaid}).count
    }
}
</code>```

Is it best practice to use functions or computed properties in the 2 cases indicated above?

答:
I would say it depends on complexity of calculation vs. usage frequency.

If it's O(1) / *, then use computed property.

If it's O(N)+ / rare-use, then use function.

If it's O(N)+ / frequent-use, think whether in the future you might decide to use caching or other "smart" techniques to compensate for the complexity, if "yes" then use property, if "no-no-no, it's just heavy" then use function.

Title: Swift functions vs computed properties


问:
Disadvantages of vertical user stories
The agile approach is to structure the work into vertical user stories and deliver a focused but fully functioning piece of the application from end-to-end. Because this is the new approach to building software I read a lot of literature about why this is better than horizontal stories but I do not find much about the disadvantages to this approach.

I already drank the agile cool-aid and I too agree that vertically slicing the cake has much advantages over horizontal slicing. Here is a short list of disadvantages that I could come up with:

A developer might initially be slower at implementing a feature because s/he must understand all the technologies required to develop the story (UI + service layer + data access + networking, etc...)

Overall architecture design (crating the backbone of the application) does not really fit this mantra (however some might argue that it is part of a user story to develop/change the overall architecture)

What are some more drawbacks of vertically slicing user stories?

Note: The reason I am asking this question now is because I am going to attempt to convince a team to start writing stories the 'vertical way' and I want to be able to bring up the possible trade-offs ahead of time so they won't consider the approach a failure when they are faced with the drawbacks.

答:
I've been thinking about this exact question a lot.

I think it's important to distinguish between slicing by individual responsibilities vs. slicing by team responsibilities. I'll focus this answer mainly on slicing teams.

For some background: I have worked in projects with full-stack developers, single-tier developers, vertical (full-stack) teams, horizontal (single-tier) teams, and diagonal teams. By diagonal team I mean containing all the tiers needed for a story but not necessarily all the tiers in the system, and also possibly containing multiple developers focusing on the same tier(s); in other words vertical in spirit but maybe somewhat horizontal in appearance or in implementation detail.

Recently I have worked in a group that transitioned from horizontal teams to diagonal (nearly vertical) teams. It has been particularly instructional to see the same group of people aligned two different ways. It makes some advantages and disadvantages quite clear.

I'll round up my opinion so far with the following summary comparison:

Horizontal Teams

Advantages:

Fosters good separation of concerns and loosely coupled tiers

Much easier workload distribution management

Easy for specialist technical lead to manage

Fosters intra-tier collaboration, best practices, pride, and a culture of excellence

Aligns with natural/emergent communication patterns

Disadvantages:

Can lead to isolation of tiers and thus hinder inter-tier communication

Enables tier "bubble" culture if unmitigated

Difficult to take advantage of generalist leadership

Hinders generalists

Vertical/Diagonal Teams

Advantages:

All the parts of a user story in one team ("one stop shop")

Specifically assists delivering n-tier stories in a single sprint (although do you really need that?)

Fosters inter-tier collaboration and growth of generalist skills

Supports generalists

Disadvantages:

Much more difficult workload distribution management

Enables poor separation of concerns and tightly coupled tiers

Hinders specialization by curtailing intra-tier communication; it is difficult to see how a culture of excellence could arise out of this structure without adding mitigating horizontal/specialist behaviors

I do not think team membership has a one-size-fits-all solution. It seems pretty straightforward, however, that the vertical team lines up better for organizations requiring generalization. If your engineers are generalists and like working full stack, that's a pretty good reason to consider vertical teams. The horizontal team lines up better for organizations requiring specialists. If your engineers are specialists, that's a pretty good reason to consider horizontal teams.

As others have mentioned, secondary structures/behaviors that slice the other direction can help mitigate the drawbacks of either system. One interesting mitigating factor is sprint duration. Short sprints render some of the disadvantages of horizontal teams more tolerable. If you can build the backend this week and the frontend next week, that might be fast enough?

To apply some of these proposed principles to a real-world problem... I will say that the horizontal slices have worked quite well for a very real SaaS development team I've worked on that was solving very challenging technical problems in every tier (where specialization was in my opinion incredibly important), where frequency of delivery (and reliability at a high granularity/frequency) was critical to business success. Please note that this conclusion is for a very particular real-world team, not a general statement of superiority of horizontal slicing.

One caveat: I am probably biased against believing claims of generalist abilities by any individual in the modern software development world without significant proof, although I have known a few rare exceptional generalists. I feel that generality is a tall (vertical?) order indeed, particularly as each tier grows in complexity and with the proliferation of alternative languages/platforms/frameworks/deployments, each meeting different needs. These days especially, a jack of all trades can quite easily be a master of none. Also, anecdotally, I find most individuals want to specialize quite a bit, again with some exceptions.

Title: Disadvantages of vertical user stories


问:
Balanced folder increment
I want to map an integer (let's say 32bits) to a valid path.
The integer is an autoincrement value stored in the database.

I also don't want at any case any folder to have more than N subfolders.
That is because in WIN-NTFS (for example) after a specific number (around 1000) things are going really slow.

So I devised a pattern where each integer is mapped to hex groupped in two digits.
That creates 4 folders for each integer

For example:

```<code>1 -> '00/00/00/01'
2000 -> '00/00/07/D0'
70000 -> '00/01/11/70'
etc
</code>```

All nice and well.

But if you notice after creating the first 257 entries

```<code>the folder '00/00/00' will have 256 entries ('00' to 'FF')
folder '00/00/01' will have one entry
folder '00/00' will have 2 entries ('00' and '01')
and last folder '00' will have just one entry.
</code>```

The graph is higly unbalanced, the OS to finally find the folder '00/00/00/55' will have to search between 1+1+2+256 = 260 entries. If the graph was balanced it would be a search of 4 * Pow(257,1/4) =~ 16 entries

And my question is:

Is anyway I can transform the integer A to an integer A' that has the following properties:

It's 1:1 transformation

Can be inversed (for each A' I can can easily find A)

For each 1..N, creating folders using the A' hex value, each folder has no more than Pow(N,1/4) entries

EDIT:
I did test the two ciphers. The problem is that crypt functions output the whole 32bit range. I mean after 1000 increments and after each byte has a random value, the root folder has 256 different values (subfolders) and each of them have 1 or 2 entries. It's the same situation I started with. It's only inversed

答:
Start with the modulo operation. That gives you X folders to start. As your ids grow, add an offset. An example, groups of 10 folders, 10 files per folder:

```<code>id < 100 : id % 10
Folders F0 through F9 -> Files are added in order, one in each,
then two, then... all the way to 10.

id >= 100 && id < 200: (id % 10) + 10
Folders F10 through F19 -> Files are added in order, et cetera

id >= 200 && id < 300: (id % 10) + 20
Folder F20 through F39

Etc...
</code>```

Of course, you'll want a different modulo (# of folders per group) and files per folder (1000?).

Title: Balanced folder increment

Body:
Start with the modulo operation. That gives you X folders to start. As your ids grow, add an offset. An example, groups of 10 folders, 10 files per folder:

id < 100 : id % 10
Folders F0 through F9 -> Files are added in order, one in each,
then two, then... all the way to 10.

id >= 100 && id < 200: (id % 10) + 10
Folders F10 through F19 -> Files are added in order, et cetera

id >= 200 && id < 300: (id % 10) + 20
Folder F20 through F39

Etc...

Of course, you'll want a different modulo (# of folders per group) and files per folder (1000?).


问:
Is there a standard way to indicate that a function returns a new pointer?
Sometimes I want to delegate the construction of objects that a class owns to a separate function. Something like

```<code>Vertex* new_vertex(const Options& options) {
  // do stuff...
  return new Vertex(...);
}
</code>```

where the function is only intended to be used to within a class that owns the Vertex. Clearly this function can cause some memory-leaking confusion, so I want to make it as clear as possible. Is there a naming convention for such functions?

答:
Yes, there are dozens of "standards" about this

The answer recommending unique_ptr is probably the best answer, but if you're looking at raw pointers, everyone's developed their own standard.

Generally speaking functions named create_____ or new______ or alloc_____ tend to imply a new object.

However

Consider that you're mixing behaviors.  You don't actually care whether this is a new instance of an object or not.  What you care about is whether the caller is responsible for destroying the object or not.  There are many APIs which hand over the responsibility for an existing object, and those functions will need a matching naming scheme. Perhaps give______.

If you're willing to step a little away from C++...

If you're willing to consider Objective-C to be similar enough to C++ to be a source for an answer, there's actually a real answer in that language.  Objective-C manages the lifespan of objects using reference counts.  They needed a way to describe whether you were being given responsibility for an object, or merely a reference to an existing object.  If you get the answer wrong, you get the ref-counts wrong and lose objects.  Accordingly they made a rule: every object you are returned is owned by someone else (so you must increment and decrement the ref count yourself), except for creation calls which pass an already incremented pointer to you (you only have to decrement).  These calls were identified by the method name.  Methods starting with alloc new copy or mutableCopy always returned a new object.  So there, the standard was enforced by the language.


问:
Can a pimpl variation be implemented without any performance penalty?
One of the issues of pimpl is the performance penalty of using it (additional memory allocation, non-contiguous data members, additional indirections, etc..). I would like to propose a variation on the pimpl idiom that will avoid these performance penalties at the expense of not getting all the benefits of pimpl. The idea is to leave all private data members in the class itself and move only the private methods to the pimpl class.
The benefit compared to basic pimpl is that the memory remains contiguous (no additional indirection). The benefits compared to not using pimpl at all are:

It hides the private functions.

You can structure it so that all these functions will have internal linkage and allow the compiler to more aggressively optimize it.

So my idea is to make the pimpl inherit from the class itself (sounds a bit crazy I know, but bear with me).
It would look something like this:

In A.h file:

```<code>class A
{
    A();
    void DoSomething();
protected:  //All private stuff have to be protected now
    int mData1;
    int mData2;
//Not even a mention of a PImpl in the header file :)
};
</code>```

In A.cpp file:

```<code>#define PCALL (static_cast<PImpl*>(this))

namespace //anonymous - guarantees internal linkage
{
struct PImpl : public A
{
    static_assert(sizeof(PImpl) == sizeof(A),
                  "Adding data members to PImpl - not allowed!");
    void DoSomething1();
    void DoSomething2();
    //No data members, just functions!
};

void PImpl::DoSomething1()
{
    mData1 = bar(mData2); //No Problem: PImpl sees A's members as it's own
    DoSomething2();
}

void PImpl::DoSomething2()
{
    mData2 = baz();
}

}
A::A(){}

void A::DoSomething()
{
    mData2 = foo();
    PCALL->DoSomething1(); //No additional indirection, everything can be completely inlined
}
</code>```

As far as I see there are absolutely no performance penalties in using this vs no pimpl and some possible performance gains and cleaner header file interface. One disadvantage this has vs standard pimpl is that you can't hide the data members so changes to those data members will still trigger a recompilation of everything that depends on the header file. But the way I see it, it's either get that benefit or the performance benefit of having the members contiguous in memory (or do this hack - "Why Attempt #3 is Deplorable"). Another caveat is that if A is a templated class the syntax gets annoying (you know, you can't use mData1 directly, you need to do this->mData1, and you need to start using the typename and maybe template keywords for dependent types and templated types, etc.). Yet another caveat is that you can no longer use private in the original class, only protected members, so you can't restrict access from any inheriting class, no just the pimpl. I tried but couldn't get around this issue. For example, I tried making the pimpl a friend template class in the hopes of making the friend declaration broad enough to allow me to define the actual pimpl class in an anonymous namespace, but that just doesn't work. If anyone has any idea of how to keep the data members private and still allow an inheriting pimpl class defined in an anonymous namepsace to access those, I'd really like to see it! That would eliminate my main reservation from using this.

I feel though, that these caveats are acceptable for the benefits of what I propose.

I tried looking online for some reference to this "function-only pimpl" idiom but couldn't find anything. I'm really interested in what people think about this. Are there other issues with this or reasons I shouldn't use this?

UPDATE:

I've found this proposal that more or less tries to accomplish exactly what I am, but doing so by changing the standard. I completely agree with that proposal and hope it will make it into the standard (I know nothing of that process so I have no idea of how likely that's to happen). I'd much rather have it possible to do this through a built in language mechanism. The proposal also explains the benefits of what I'm trying to achieve much better than me. It also doesn't have the issue of breaking encapsulation like my suggestion has (private -> protected). Still, until that proposal makes it into the standard (if that ever happens), I think my suggestion makes it possible to get those benefits, with the caveats I listed.

UPDATE2:

One of the answers mentions LTO as a possible alternative to getting some of the benefits (more aggressive optimizations I'm guessing). I'm not really sure exactly what goes on in various compiler optimization passes but I do have a bit of experience with the resulting code (I use gcc). Simply putting the private methods in the original class will force those to have external linkage.

I might be wrong here, but the way I interpret that is that the compile-time optimizer cannot eliminate the function even if all its call instances are completely inlined inside that TU. For some reason even LTO refuses to get rid of the function definition even if it seems that all the call instances in the entire linked binary are all inlined. I found some references stating that it's because the linker doesn't know if you'll somehow still call the function using function pointers (though I don't understand why the linker can't figure out that the address of that method is never taken).

This is not the case if you use my suggestion and put those private methods in a pimpl inside an anonymous namespace. If those get inlined, the functions will NOT appear in (with -O3, that includes -finline-functions) the object file.

The way I understand it, the optimizer, when deciding whether or not to inline a function, takes into account its impact on code size. So, using my suggestion I'm making it slightly "cheaper" for the optimizer to inline those private methods.

答:
With all due respect and not with any intent of killing this excitement, I don't see any practical benefit this serves from a compile-time perspective. A lot of the benefits of pimpls are going to come from hiding user-defined type details. For example:

```<code>struct Foo
{
    Bar data;
};
</code>```

... in such a case, the heaviest cost of compilation comes from the fact that, in order to define Foo, we must know the size/alignment requirements of Bar (which means we must recursively require the definition of Bar).

If you aren't hiding the data members, then one of the most significant benefits from a compile-time perspective is lost. Also there's some potentially dangerous-looking code there but the header isn't getting any lighter and the source file is getting heavier with more forwarding functions, so it's likely to increase, rather than decrease, compilation times overall.

Lighter Headers is the Key

To get a decrease in build times, you want to be able to show a technique that results in a dramatically lighter-weight header (typically by allowing you to no longer recursively #include some other headers because you hid details which no longer require certain struct/class definitions). That's where genuine pimpls can have a significant effect, breaking off cascading chains of header inclusions and yielding far more independent headers with all the private details hidden away.

Safer Ways

If you want to do something like this anyway, it'll also be a whole lot simpler to use a friend defined in your source file rather than one which inherits the same class which you don't actually instantiate with pointer casting tricks to call methods on an uninstantiated object, or simply use free-standing functions with internal linkage inside the source file which receive the appropriate parameters to do the necessary work (either of these could at least allow you to hide some private methods from the header for a very trivial savings in compilation times and a little bit of wiggle room to avoid cascading recompilation).

Fixed Allocator

If you want the cheapest kind of pimpl, the main trick is to use a fixed allocator. Especially when aggregating pimpls in bulk, the biggest killer is the loss of spatial locality and the additional compulsory page faults when accessing the pimpl for the first time. By preallocating memory pools that pool off memory to pimpls being allocated and return the memory to the pool instead of freeing it on deallocation, the cost of a boatload of pimpl instances diminishes dramatically. It's still not free though from a performance standpoint, but a whole lot cheaper and far more cache/page-friendly.

Body:
With all due respect and not with any intent of killing this excitement, I don't see any practical benefit this serves from a compile-time perspective. A lot of the benefits of pimpls are going to come from hiding user-defined type details. For example:

struct Foo
{
    Bar data;
};

... in such a case, the heaviest cost of compilation comes from the fact that, in order to define Foo, we must know the size/alignment requirements of Bar (which means we must recursively require the definition of Bar).

If you aren't hiding the data members, then one of the most significant benefits from a compile-time perspective is lost. Also there's some potentially dangerous-looking code there but the header isn't getting any lighter and the source file is getting heavier with more forwarding functions, so it's likely to increase, rather than decrease, compilation times overall.

Lighter Headers is the Key

To get a decrease in build times, you want to be able to show a technique that results in a dramatically lighter-weight header (typically by allowing you to no longer recursively #include some other headers because you hid details which no longer require certain struct/class definitions). That's where genuine pimpls can have a significant effect, breaking off cascading chains of header inclusions and yielding far more independent headers with all the private details hidden away.

Safer Ways

If you want to do something like this anyway, it'll also be a whole lot simpler to use a friend defined in your source file rather than one which inherits the same class which you don't actually instantiate with pointer casting tricks to call methods on an uninstantiated object, or simply use free-standing functions with internal linkage inside the source file which receive the appropriate parameters to do the necessary work (either of these could at least allow you to hide some private methods from the header for a very trivial savings in compilation times and a little bit of wiggle room to avoid cascading recompilation).

Fixed Allocator

If you want the cheapest kind of pimpl, the main trick is to use a fixed allocator. Especially when aggregating pimpls in bulk, the biggest killer is the loss of spatial locality and the additional compulsory page faults when accessing the pimpl for the first time. By preallocating memory pools that pool off memory to pimpls being allocated and return the memory to the pool instead of freeing it on deallocation, the cost of a boatload of pimpl instances diminishes dramatically. It's still not free though from a performance standpoint, but a whole lot cheaper and far more cache/page-friendly.


问:
Unit testing an API client and wrappers
I've been going round in circles trying to figure out the best way to unit test an API client library I'm developing. The library has a Client class which basically has a 1:1 mapping with the API, and an additional Wrapper class which provides a more user-friendly interface over the top of the Client.

```<code>Wrapper --> Client --> External API
</code>```

I first wrote a bunch of tests against both Client and Wrapper, effectively just testing that that they forward to the appropriate functions of whatever the operate on (Wrapper operates on Client, and Client operates on a HTTP connection). I started feeling uncomfortable with this, however, because I feel like I'm testing the implementation of these classes, rather than the interface. In theory, I could change the classes to have another perfectly valid implementation, but my tests would fail because the functions I expected to be called aren't being called. That sounds like fragile tests to me.

After this, I thought about the interface of the classes. The tests should verify that the classes actually do the job they're meant to do, rather than how they do it. So how can I do this? The first thing that comes to mind is stubbing the external API requests. However, I'm nervous about oversimplifying the external service. A lot of the examples of stubbed APIs I've seen just give canned responses, which sounds like a really easy way to only test that your code happens to run correctly against your fake API. The alternative is mocking the service, which is just infeasible, and would need to be kept up to date whenever the real service changes - that feels like overkill and waste of time.

Finally, I read this from another answer on the programmers SE:

The job of a remote API client is to issue certain calls - no more, no less. Therefore, its test should verify that it issues those calls - no more, no less.

And now I'm more or less convinced - when testing Client, all I need to test is that it makes the correct requests to the API (Of course, there's always the possibility that the API will change but my tests continue to pass - but that's where integration tests would come in useful). Since Client is just a 1:1 mapping with the API, my concern before about changing from one valid implementation to another doesn't really apply - there's only one valid implementation for each method of Client.

However, I'm still stuck with the Wrapper class. I see the following options:

I stub out the Client class and just test that the appropriate methods are called. In this way, I'm doing the same as above but treating the Client as a stand-in for the API. This puts me right back where I started. Once again, this gives me the uncomfortable feeling of testing implementation, not interface. The Wrapper could very well be implemented using a completely different client.

I create a mock Client. Now I have to decide how far to go with mocking it - creating a complete mock of the service would take a lot of effort (more work than has gone into the library itself). The API itself is simple, but the service is quite complex (it's essentially a datastore with operations on that data). And again, I will have to keep my mock in sync with the real Client.

I just test that the appropriate HTTP requests are being made. This means that Wrapper will be calling through a real Client object to make those HTTP requests, so I'm not actually testing it in isolation. This makes it a bit of a terrible unit test.

So I'm not particularly happy with any of these solutions. What would you do? Is there a right way to go about this?

答:
TLDR: Despite the difficulty, you should stub the service and use for client unit testing.

I'm not as certain that the "job of a remote API client is to issue certain calls, no more, no less...", unless the API only consists of endpoints which always return a fixed status, and neither consume nor produce any data. This would not be the most useful API...

You'd also want to check that the client not only sends the correct requests, but that it properly handles response content, errors, redirects, etc. And test for all these cases.

As you note, you should have integration tests that cover the full stack from wrapper -> client -> service -> DB and beyond, but to answer your main question, unless you have an environment where integration tests can be run as part of every CI build without a lot of headaches (shared test databases, etc.), you should invest the time in creating a stub of the API.

The stub will let you create a working implementation of the service, but without having to implement any layer below the service itself.

You could consider using a DI-based solution to accomplish this, with an implementation of the Repository pattern underneath the REST resources:

Replace all functional code in the REST handlers with calls to an IWhateverRepository.

Create a ProductionWhateverRepository with the code that was extracted from the REST resources, and a TestWhateverRespository which returns canned responses for use during unit testing.

Use the DI container to inject either the ProductionWhateverRepository or TestWhateverRepository DLL/class, etc. depending on configuration.

Anyway, unless stubbing and/or refactoring the service is out of the question either politically or practically, I'd probably undertake something similar to the above. If not possible, then I'd make sure to have really good integration coverage and run them as often as possibly given your available test setup.

HTH

Title: Unit testing an API client and wrappers


问:
Can this argument be enough?
We have two C++ classes named Important and Small

The class Small use a few methods and attributes from the class Important, but not all.

Since our application is performance critical, instead of copying all attributes (possibly pointers) of Important that are needed by Small and redefine the few methods in Small, we decided to just let Small hold a pointer on Important.

Can performance justify such a design choice?

答:
Can performance justify such a design choice?

With so little information, I think the advice is going to be pushed towards suggestions of profiling and measuring and warnings about premature optimization. But I'll try to give you the benefit of the doubt.

Let's apply a data-oriented design mindset which begins with the idea of the most optimal data representation, and works our way up to interfaces from there. The most useful aspect of this exercise is still going to be the public interfaces we design, the consideration of data representations is mainly to ensure that we have an interface that can leave wiggle room to optimize without cascading breakages in the system.

Data-Oriented Design

Since our application is performance critical, instead of copying all
  attributes (possibly pointers) of Important that are needed by Small
  and redefine the few methods in Small, we decided to just let Small
  hold a pointer on Important.

Some assumptions I'm going to make to narrow the scope:

There are a boatload of these Small* instances.

The initialization phase where they are created as a subset of Important's data is separate and outside of your critical code paths, not interleaved (otherwise your existing suggestion might be the best route).

The critical path is going to loop through a boatload of these Small instances.

The fields of Important itself, outside of the subset represented by Small, are cold.

The fields of Important do not change past the initialization step (their pointees could change if there are pointer fields, but the pointer addresses would not change).

One-to-One

Provided that there's a one-to-one relationship of a Small*'s subset of data fields to an Important (no redundancy), then typically the fastest way to go is to actually copy and duplicate the data of Important in small.

Since Important is cold data according to our assumptions, that allows Small to take on a more contiguous nature, and for more of the relevant data to fit into a cache line without being intermixed with irrelevant data.

Many-to-One

If that's wrong and there's a whole lot of redundancy between Small* instances (i.e., a many-to-one relationship between Small references to an Important field), then duplicating the data could do more harm than good.

In that case, pointing to Important can start to show a favorable advantage, as we're playing to temporal locality with Important fields often sitting in a cache line and reducing Small down to the size of a single pointer.

To Duplicate or Not to Duplicate

So the choice of whether or not to duplicate depends on the level of redundancy and whether the initialization phase of a small is outside of the critical paths. If you want to know to what level of redundancy, consider the total size of all Small* instances if those fields from Important were duplicated. If that size is not larger than the sum of all Important fields, then copying the relevant fields to Small might be a safe bet (provided Important doesn't need to be accessed in critical paths at all, that it's truly cold after that point).

With little or no redundancy, and Important being cold, then actually hot/cold field splitting with redundancy to get the hot side of the split can actually help a lot (as counter-intuitive as it may seem).

Last but not least, there should be a boatload of Small* instances being instantiated and accessed. If there aren't, then this is worrying about something that shouldn't be worried about, as you'll likely benefit a lot from temporal locality either way.

Title: Can this argument be enough?


问:
Improving the efficiency of containers with dynamically allocated objects
This is not strictly related to C++ but its type system serves to illustrate the problem well.

Assume:

We have a generic template Container<T> (such as a std::vector<T>) which stores an unspecified number of elements of the same type T on the heap.  Each element is allocated and deallocated via the constructor and destructor of T.

A type M that stores m elements on the heap (so M itself is a kind of container).  However, the value of m is not known at compile time, so it cannot be used as a template parameter to M.

Problem:

If we try to use a type Container<M>, accessing the elements of M inside this container would require two pointer dereferences, which in general has worse performance than if all elements of M were laid out contiguously.

Non-ideal solution:

Create a separate class ContainerFixed<T> that manages the memory of T directly, if T is assumed to have the same size throughout the container.  T would also have to exchange information about its storage with the containing class.  However, if we implement another kind of container, then we have to repeat this process again.

The problem arises because the container class is oblivious of the storage requirements of T so it defers the allocation to T itself; if the container had known that T only requires a fixed (though not known at compile time) number of elements then this issue could have been avoided.

Now I feel as though that if there was some way to communicate to the container that M has a definite size m (as in M<m>, which is not legal in C++), then from the type signature of Container<M<m> > one can potentially deduce that a faster allocation scheme is possible.  (It's a bit like dependent types, in a way.)  That is, any Container1<Container2<m> > can be allocated more efficiently as a "flattened" container.

What would be a more general solution to this problem?  I don't think this is something that can be easily solved in C++ (feel free to prove me wrong), so I would certainly like to hear if this is something that other languages can solve in a much simpler way (perhaps with more sophisticated type systems).

答:
Now I feel as though that if there was some way to communicate to the
  container that M has a definite size m (as in M, which is not legal
  in C++), then from the type signature of Container > one can
  potentially deduce that a faster allocation scheme is possible. (It's
  a bit like dependent types, in a way.) That is, any
  Container1 > can be allocated more efficiently as a
  "flattened" container.

This is not a conceptually simple problem at all, because you have two competing aggregates here (the class M and the vector) which want to be independently-sized dynamically.

From a compiler and language design standpoint with a focus on standard approaches to type systems, this is an incredibly difficult problem and would require some fusion/coalescing of the two aggregate concepts.

In C++, if you want the most efficient solution here, you typically have to implement this fused aggregate (the container and M as a single class fusing the two ideas together). It's a real hassle, but if you really need the extra performance gain, that's typically the way to go. The alternate route is to reach for a custom allocator under the hood (but that's almost like implementing a separate data structure still, and still exposes the overhead of pointers in the vector which degrades locality of reference, though not as much as lacking the custom allocator).

A language that can tackle this might be ideal for today's day and age of predominant memory optimization in performance-critical fields, but it would take on a very unusual nature with its type system. The type system would most likely be designed to interact with containers with a non-scalar mindset.

You might be able to also design something like this in C++ but it would tend to require a new set of containers which double over as both allocator and data structure where we can request to instantiate five elements of T, but in a way that yields a new aggregate, M, e.g., with associated metadata which lets you access that small contiguous block as though it were a separate aggregate of T's on its own.

It also leaves a question as to the homogeneity and alignment requirements of the data, because M != m T's, e.g. It would have that metadata associated which stores things like size potentially and possibly other data associated to the m T's, so it leaves the question of where to store and align that within the container (or possibly outside in parallel, but outside may hinder performance and would imply a pointer/index overhead into the container's contents once more rather than relative addressing), along with construction/destruction concerns for M which are separate from m T's.

Another thing is that if M is allowed to resize m while residing within the container, now there's a whole new and even more complex dynamic going on and solutions like vector would become ill-suited to the problem since they'd require linear-time complexity to resize a single M within it. M as an aggregate would also have to avoid storing pointers to the vector either way, as such pointers would be invalidated whenever the vector's capacity is changed, whenever an element is removed from anywhere other than the back, etc. Basically this design, to be optimal, needs the idea of container and sub-container tightly coupled together in ways that would be incredibly difficult to do in a generalized way through a new kind of type system.


问:
What is the point of using lists over vectors, in C++?
I've run 3 different experiments involving C++ lists and vectors.

Those with vectors proved more efficient, even when a lot of insertions in the middle were involved.

Hence the question: in which case do lists make more sense than vectors?

If vectors seem more efficient in most cases, and considering how alike their members are, then which advantages are left for lists?

Generate N integers and put them in a container so that the container remains sorted. The insertion has been performed naively, by reading elements one by one and inserting the new one right before the first larger one.

With a list, time goes through the roof when dimension increases, compared to vectors.

Insert N integers at the end of the container.

For lists and vectors, time increased by the same order of magnitude, though it was 3 times faster with vectors.

Insert N integers in a container.

Start timer.

Sort the container using list.sort for lists, and std::sort for vectors.
Stop timer.

Again, time increases by the same order of magnitude, but it is in average 5 times faster with vectors.

I might continue to perform tests and figure out a couple of examples where lists would prove better.

But the joint experience of you guys reading this message might provide more productive answers.

You might have come across situations where lists were more convenient to use, or performed better?

答:
The lack of inherent cache/page-friendliness of linked lists tend to make them almost dismissed entirely by a lot of C++ developers, and with good justification in that default form.

Linked Lists Can Still Be Wonderful

Yet linked lists can be wonderful when backed by a fixed allocator that gives them back that spatial locality they inherently lack.

Where they excel is that we can split a list into two lists, for example, by simply storing a new pointer and manipulating a pointer or two. We can move nodes from one list to another in constant time by mere pointer manipulation, and an empty list can simply have the memory cost of a single head pointer.

Simple Grid Accelerator

As a practical example, consider a 2D visual simulation. It has a scrolling screen with a map that spans 400x400 (160,000 grid cells) used for accelerating things like collision detection between millions of particles moving around at each frame (we avoid quad-trees here as they actually tend to perform worse with this level of dynamic data). A whole bunch of particles are constantly moving around at every frame, meaning they go from residing in one grid cell to another constantly.

In this case, if each particle is a singly-linked list node, each grid cell can start off as just a head pointer which points to nullptr. When a new particle is born, we just put it in the grid cell it resides by setting the head pointer of that cell to point to this particle node. When a particle moves from one grid cell to the next, we just manipulate pointers.

This can be vastly more efficient than storing 160,000 vectors for each grid cell and pushing back and erasing from the middle all the time on a frame-by-frame basis.

std::list

This is for hand-rolled, intrusive, singly-linked lists backed by a fixed allocator though. std::list represents a doubly-linked list and it might not be nearly as compact when empty as a single pointer (varies by vendor implementation), plus it's kind of a pain to implement custom allocators in std::allocator form.

I must admit I never use list whatsoever. But linked lists can be still wonderful! Yet they're not wonderful for the reasons people are often tempted to use them, and not so wonderful unless they're backed by a very efficient fixed allocator which mitigates a lot of at least the compulsory page faults and cache misses associated.


答:
In short, there is no good reason for using std::list<>:

If you need an unsorted container, std::vector<> rules.

(Delete elements by replacing them with the last element of the vector.)

If you need a sorted container, std::vector<shared_ptr<>> rules.

If you need a sparse index, std::unordered_map<> rules.

That's it.

I find that there is only one situation where I tend to use a linked list: When I have preexisting objects that need to be connected in some way to implement some additional application logic. However, in that case I never use std::list<>, rather I resort to a (smart) next pointer inside the object, especially since most use cases result in a tree rather than a linear list. In some cases, the resulting structure is a linked list, in others, it is a tree, or a directed acyclic graph. The primary purpose of these pointers is always to build logical structure, never to manage objects. We have std::vector<> for that.

Title: What is the point of using lists over vectors, in C++?

Body:
I've run 3 different experiments involving C++ lists and vectors.

Those with vectors proved more efficient, even when a lot of insertions in the middle were involved.

Hence the question: in which case do lists make more sense than vectors?

If vectors seem more efficient in most cases, and considering how alike their members are, then which advantages are left for lists?

Generate N integers and put them in a container so that the container remains sorted. The insertion has been performed naively, by reading elements one by one and inserting the new one right before the first larger one.

With a list, time goes through the roof when dimension increases, compared to vectors.

Insert N integers at the end of the container.

For lists and vectors, time increased by the same order of magnitude, though it was 3 times faster with vectors.

Insert N integers in a container.

Start timer.

Sort the container using list.sort for lists, and std::sort for vectors.
Stop timer.

Again, time increases by the same order of magnitude, but it is in average 5 times faster with vectors.

I might continue to perform tests and figure out a couple of examples where lists would prove better.

But the joint experience of you guys reading this message might provide more productive answers.

You might have come across situations where lists were more convenient to use, or performed better?