答:
Yes, GPL'd software can be sold.  The GPL FAQ[1] is pretty clear on this point.

Also, software cannot really be "open source" and have a "you can't sell this" limitation.  Such a limitation violates plank #1 of the Open Source Definition[2].
Of course not everybody accepts the OSI definition, but in pretty much every practical regard, nobody considers software Open Source if you put in a restriction on re-selling it.

Perhaps the combination you are looking for can be found in one of the Microsoft Shared Source[3] licenses.  You might consider the Microsoft Research Shared Source License Agreement[4], for example.

All of that said, why are you guys so set against resale?  Doing something like that is really going to make your stuff a lot less accessible / useful to people.

Title: Can GPL-licensed software be resold?


问:
Why do XSLT editors insert tab or space characters into XSLT to format it?
All XSLT editors I've tried till now add tab or space characters to the XSLT to indent it for formatting. This is done even in places within the XSLT where these characters are significant to the XSLT processor.

XSLT modified for formatting in this way can produce output very different to that of the original XSLT if it had no formatting. To prevent this, xsl:text elements or other XSLT must be added to a sequence constructor to help separate formatting from content, this additional XSLT impacts on maintainability. Formatting characters also adversely impact on general usability of the tool in a number of ways (this is why word-processors don't use them I guess) and add to the size of the file.

As part of a larger project I've had to develop a light-weight XSLT editor, it's designed to format XSLT properly, but without tab or space characters, just a dynamic left-margin for each new line. The XSLT therefore doesn't need additional elements to separate formatting tab or space characters from content. The problem with this is that if XSLT from this editor is opened in other XSLT editors, characters will be added for formatting reasons and the XSLT may therefore no longer behave as intended.

Why then do existing XSLT editors use tabs or spaces for formatting in the first place?

I feel there must be valid reasons, perhaps historical, perhaps practical. An answer will help me understand whether I need to put compatibility options in place in my XSLT editor somehow, whether I should simply revert to using tabs or spaces for both XSLT content and formatting (though this seems like a backwards step to me), or even whether enough XSLT users might be able to persuade their tools vendors to include alternative formatting methods to tabs or spaces.

Note: I provided an XSLT sample demonstrating formatting differences in this answer to the question: Tabs versus spaces—what is the proper indentation character for everything, in every situation, ever?

答: Because those writing the XSLT editor, don't use it themselves to write XSLT, and confuse it with plain XML where whitespace matters less.</p>

ContentLicense: CC BY-SA 3.0


问:
Is there any formal research in FizzBuzz Question Effectiveness?
After seeing this question today on variation of the FizzBuzz interview question, as well as seeing other questions related to it around, I have to ask: is there any formal research on how effective this is as an interview technique? There are plenty of folks who say that it filters out some crazy-sounding percentage of candidates (95%+ in some cases) but how good is it for finding good programmers/developers?

There has been some research that shows that soft skills might be better indicators than hard skills for choosing a good candidate for a job role. As well, there might be some intermediate reasons for so many candidates failing this test (nervousness, thinking "it's a trick", etc).

Based on the comments so far, it looks like the idea behind FizzBuzz questions is to determine whether or not the person has good (enough) coding skills to be further considered. I'm not totally convinced FizzBuzz actually does this. Also, remember that FizzBuzz filters a very large percentage of candidates very early in the hiring process, which could mean that significant numbers of good candidates are being removed early on because they can't solve silly problems fast enough.

Also, I'll point out that looking at FizzBuzz effectiveness is something that can completely be done in a quantitative manner. This is unlike looking at "fit" or "passion" which are highly variable and highly unscientific (but still quite important for new hiring decisions).

答:
It's been a long time since I read up on job interview research, (so I can't site specifics, for which I apologize) but the general rule is that people hire on the basis of soft skills but there is no correlation between that and performance.  Testing for specific skills can work, for personality does not (according to measurable data).

Almost everyone believes their special interview techniques work, the data says you should probably not bother interviewing (the "tell me about yourself" part of the interview, as opposed to objective testing) since candidates selected by interviewers are not any better but interviewers do show biases towards extroverts, people demographically similar to the interviewer, tall people, attractive people, etc.   (Arguably you should hire people who do well on tests and bad on the rest of the interview, since they are apparently just as good on the job but may find it harder to leave your company).

I kind of expect to get flamed for this, usually anyone I tell this to says "but we use method X and it really works for us", but unless you

hire some people who don't pass your interview process,

don't tell their coworkers who passed and who didn't, and

compare performance of those who passed with those who didn't, using previously agreed on objective criteria

you really have very little idea whether your process works.  Unfortunately the effectiveness of interviewing is inherently difficult to evaluate.

If you are wondering, experiments do things like ask people to evaluate candidates based on interview transcripts, from candidates who have actually already been hired (among many other techniques).  Ideally experimenters would have people do interviews, pick candidates, erase the memory of the interviewer, randomly select who to hire from among the candidates, and compare the candidates performance using accurate, objective criteria versus the ratings given by the interviewers, but that experiment is hard to pull off.

So, though I haven't seen FizzBuzz specific research, it is the kind of thing which can show effectiveness in scientific testing.  If it screens out 95% of candidates then I'd be curious as to why - it was invented to be so absurdly easy that only an incompetent programmer could fail to pass it, and it's hard to see how to dumb down FizzBuzz.  I wonder what percentage pass the "Hello world" test?  The "make the computer do something, anything" test?


问:
What's the proper way to organize ViewControllers and XIB?
I am developing a very simple iPhone game with this view hierarchy:

```<code>Main Menu View
  └> New Game View
  |    └> Player vs Computer Game View
  |    |    └> Pause View
  |    |    └> End Turn View
  |    |    └> End Game View
  |    |
  |    └> Player vs Player (offline) Game View
  |         └> Pause View
  |         └> End Turn View
  |         └> End Game View
  |
  └> Information View
</code>```

My current implementation has a single ViewController that controls every aspect of the user interface and a single XIB file that contains every View of the game.

Is this correct? It looks a bit confusing...
Should i have more ViewControllers and more XIB files? And what's the proper way to make them cooperate?

答:
Your view controllers should each handle one area full of content. In the past, the guideline was that a view controller managed a "screenful" of content. That has changed somewhat with UISplitViewController, but the idea remains sound. Even with a split view controller, each of the view controllers involved manages its own view hierarchy and has its own task.

So, if you're using a single view controller for your "main menu view", "new game view", "one player view", and "two player view", you should really think about refactoring. Using separate view controller objects for each of those will simplify your code by limiting each view controller's responsibility to one piece of game functionality. That doesn't mean that you have to have a separate class for every view, though. For example, it might be that your "player v. computer" view controller and "player v. player" view controller are each instances of the same class, but configured differently.

OwnerDisplayName: Oneiros


问:
What are the advantages of using Adobe Flex?
I've used Adobe Flex to develop a web application and I simply don't have an opinion of it, it looks good to the user and the code can't be seen for most users, but, is that it? What other advantage does Flex has?</p>

答:
As of version 4.5.1, Flex now supports Android OS, Blackberry Tablet OS, and iOS:

http://gregsramblings.com/2011/06/20/finally-its-here-flex-on-ios-android-and-blackberry-playbook/

Let me know if I'm wrong, but it looks like this is the only SDK that will support deployment to all three of those systems.

ContentLicense: CC BY-SA 2.5


问:
What is the term that describe objects representing both logic and data?
The reason I am asking this question is I want to know how to properly call an architecture where classes have either data or logic but not both. I know this goes against object orientation and encapsulation. I want to use the proper terms for discussing this architecture.

EDIT: By reading the answers I have received, I can see my question wasn't clear. I also feel the edit that was made didn't push the question in the direction I was going for.

I will restate the question in other terms.

Suppose you are working in C#, Java or some other OO language.

You have 2 designs:

DESIGN A:

```<code>class Car
{
     // data
     int numberOfWheels;
     Engine carEngine;

     // methods
     public void StartCar();
}
</code>```

DESIGN B:

```<code>class Car
{
     // this class contains only data (be it entity, DTO, whatever)
     int numberOfWheels;
     Engine carEngine;
}

class CarStarter
{
     public void StartCar(Car aCar);
}
</code>```

In DESIGN B, some classes are used as data structures/DTO/entities (they contain only data and should not contain methods). Other classes contains logic and work with the data classes.

Now suppose you have a design/architecture where DESIGN B, should be applied throughout rather than design A.

I was looking either for a term that described DESIGN B, or the OOP term/notion that consist of DESIGN A. Preferably both.

For the OOP term I guess encapsulation could be it. From Wikipedia Encapsulation

A language construct that facilitates the bundling of data with the methods (or other functions) operating on that data.

I still don't know how to call DESIGN B though.

答:
Objects have both state and behavior.

Objects that have only state and no behavior are data or data transfer objects.  I've also heard them referred to, incorrectly, as entities.

Objects that have only behavior but no state are services.


答:
Objects that contain and expose both logic (methods, properties) and data (fields) are simply "objects". Often, the overall behavior of this object is a model for some real-world concept or thing (this is after all the point of O-O design; to structure programs in terms of code objects that model real-world ideas), which means that an object must encapsulate both data about the state of a particular instance of that object, and also logic representing what an object can do; these stateful yet "rich" objects, as a collection in your codebase, are usually called the "domain" or "model".

An object containing only logic is rare; most objects need to store some sort of state. If you need one term for all of these,  There are three major subcategories I can think of that are more commonly heard of:

Static classes that organize "pure" (stateless and/or side-effect free) utility methods; these are generally "helpers" or "utility classes".

Instance classes that exist as "bridges" for communications between classes or architectural layers; these are often called "controllers" because their usual function is to direct more stateful objects to perform overarching tasks that the stateful objects should not know how to do by themselves.

Instance classes that provide a means to get state information out of an external resource. The instance class itself does not "own" the state data that is exposed; it is simply a means to an end. These are generally called "repositories"; some of them may be called "proxies" depending on the basic design pattern in which the object is used.

Classes that contain only data are generally referred to as DTOs, or Data Transfer Objects. You may also hear them called "structs", but that term is usually reserved in the C-style languages for "complex value types" like DateTime, Money, Point, Vector, etc. Sometimes, data-only classes are used as the "domain", with other classes built to perform all manipulations of that data, but this is known as an "anemic domain model" and is generally considered an anti-pattern.

Title: What is the term that describe objects representing both logic and data?

Body:
The reason I am asking this question is I want to know how to properly call an architecture where classes have either data or logic but not both. I know this goes against object orientation and encapsulation. I want to use the proper terms for discussing this architecture.

EDIT: By reading the answers I have received, I can see my question wasn't clear. I also feel the edit that was made didn't push the question in the direction I was going for.

I will restate the question in other terms.

Suppose you are working in C#, Java or some other OO language.

You have 2 designs:

DESIGN A:

```<code>class Car
{
     // data
     int numberOfWheels;
     Engine carEngine;

     // methods
     public void StartCar();
}
</code>```

DESIGN B:

```<code>class Car
{
     // this class contains only data (be it entity, DTO, whatever)
     int numberOfWheels;
     Engine carEngine;
}

class CarStarter
{
     public void StartCar(Car aCar);
}
</code>```

In DESIGN B, some classes are used as data structures/DTO/entities (they contain only data and should not contain methods). Other classes contains logic and work with the data classes.

Now suppose you have a design/architecture where DESIGN B, should be applied throughout rather than design A.

I was looking either for a term that described DESIGN B, or the OOP term/notion that consist of DESIGN A. Preferably both.

For the OOP term I guess encapsulation could be it. From Wikipedia Encapsulation

A language construct that facilitates the bundling of data with the methods (or other functions) operating on that data.

I still don't know how to call DESIGN B though.


问:
Why don't many code review tools seem to be syntax aware or provide more in-depth analysis of changes?
Why don't many code review tools seem to be syntax aware or provide more in-depth analysis of changes? Is it simply too hard to do?

I find this to be a major hole of most programmer's toolkits. From what I have seen, which admittedly is not much, code review tools just compare code line-by-line with many of them not even being able to do syntax highlighting.

Is there a solution out there that is smart enough to offer file-level, method-level code review/comparison? One of the simple problems I have is that methods get re-ordered in code and my code review software breaks down completely, but they should be able to do so much more.

I'm interested in others opinions/knowledge on the topic of code review/comparison tools.

答:
Code review tools are tools designed to be used with any programming language.

This means that in order to add file-level and/or method-level comparisons, they will need to understand the context of the language.

This in turn means both knowing about all possible languages and having a parser for them.

All of which are very difficult and error prone. So, for a commercial enterprise the question would be - which language to support first. How well? For a free option, the fact is that such a thing will take a very long time to do, even for one language.

Having a line-by-line option covers most needs already, so people don't try more.


问:
When is a version control commit too large?
I've heard in several places "Don't make large commits" but I've never actually understood whats a "large" commit. Is it large if you work on a bunch of files even if there related? How many parts of a project should you be working on at once?

To me, I have trouble trying to make "small commits" since I forget or create something that creates something else that creates something else. You then end up with stuff like this:

```
Made custom outgoing queue

Bot
-New field msgQueue which is nothing more than a SingleThreadExecutor
-sendMsg blocks until message is sent, and adds wait between when messages get
sent
-adminExist calls updated (see controller)
-Removed calles to sendMessage

Controller
-New field msgWait denotes time to wait between messages
-Starting of service plugins moved to reloadPlugins
-adminExists moved from Server because of Global admins. Checks at the channel,
server, and global level

Admin
-New methods getServer and getChannel that get the appropiate object Admin
belongs to

BotEvent
-toString() also show's extra and extra1

Channel
-channel field renamed to name
-Fixed typo in channel(int)

Server
-Moved adminExists to Controller

PluginExecutor
-Minor testing added, will be removed later

JS Plugins
-Updated to framework changes
-Replaced InstanceTracker.getController() with Controller.instance
-VLC talk now in own file

Various NB project updates and changes

---

Affected files
Modify  /trunk/Quackbot-Core/dist/Quackbot-Core.jar
Modify  /trunk/Quackbot-Core/dist/README.TXT
Modify  /trunk/Quackbot-Core/nbproject/private/private.properties
Modify  /trunk/Quackbot-Core/nbproject/private/private.xml
Modify  /trunk/Quackbot-Core/src/Quackbot/Bot.java
Modify  /trunk/Quackbot-Core/src/Quackbot/Controller.java
Modify  /trunk/Quackbot-Core/src/Quackbot/PluginExecutor.java
Modify  /trunk/Quackbot-Core/src/Quackbot/info/Admin.java
Modify  /trunk/Quackbot-Core/src/Quackbot/info/BotEvent.java
Modify  /trunk/Quackbot-Core/src/Quackbot/info/Channel.java
Modify  /trunk/Quackbot-Core/src/Quackbot/info/Server.java
Modify  /trunk/Quackbot-GUI/dist/Quackbot-GUI.jar
Modify  /trunk/Quackbot-GUI/dist/README.TXT
Modify  /trunk/Quackbot-GUI/dist/lib/Quackbot-Core.jar
Modify  /trunk/Quackbot-GUI/nbproject/private/private.properties
Modify  /trunk/Quackbot-GUI/nbproject/private/private.xml
Modify  /trunk/Quackbot-GUI/src/Quackbot/GUI.java
Modify  /trunk/Quackbot-GUI/src/Quackbot/log/ControlAppender.java
Delete  /trunk/Quackbot-GUI/src/Quackbot/log/WriteOutput.java
Modify  /trunk/Quackbot-Impl/dist/Quackbot-Impl.jar
Modify  /trunk/Quackbot-Impl/dist/README.TXT
Modify  /trunk/Quackbot-Impl/dist/lib/Quackbot-Core.jar
Modify  /trunk/Quackbot-Impl/dist/lib/Quackbot-GUI.jar
Modify  /trunk/Quackbot-Impl/dist/lib/Quackbot-Plugins.jar
Modify  /trunk/Quackbot-Impl/lib/javarebel.stats
Add /trunk/Quackbot-Impl/lib/jrebel.info
Modify  /trunk/Quackbot-Impl/nbproject/private/private.properties
Modify  /trunk/Quackbot-Impl/nbproject/private/private.xml
Modify  /trunk/Quackbot-Impl/nbproject/project.properties
Modify  /trunk/Quackbot-Impl/plugins/CMDs/Admin/reload.js
Add /trunk/Quackbot-Impl/plugins/CMDs/Operator/hostBan
Modify  /trunk/Quackbot-Impl/plugins/CMDs/Operator/mute.js
Modify  /trunk/Quackbot-Impl/plugins/CMDs/lyokofreak/curPlaying.js
Modify  /trunk/Quackbot-Impl/plugins/CMDs/lyokofreak/lfautomode.js
Modify  /trunk/Quackbot-Impl/plugins/listeners/onJoin.js
Modify  /trunk/Quackbot-Impl/plugins/listeners/onQuit.js
Modify  /trunk/Quackbot-Impl/plugins/testCase.js
Add /trunk/Quackbot-Impl/plugins/utils/whatsPlaying.js
Modify  /trunk/Quackbot-Impl/src/Quackbot/impl/SandBox.java
Add /trunk/Quackbot-Impl/vlc_http
Add /trunk/Quackbot-Impl/vlc_http/current.html
Modify  /trunk/Quackbot-Plugins/dist/Quackbot-Plugins.jar
Modify  /trunk/Quackbot-Plugins/dist/README.TXT
Modify  /trunk/Quackbot-Plugins/dist/lib/Quackbot-Core.jar
Modify  /trunk/Quackbot-Plugins/nbproject/private/private.properties
Modify  /trunk/Quackbot-Plugins/nbproject/private/private.xml
Modify  /trunk/Quackbot-Plugins/src/Quackbot/plugins/JSPlugin.java
Add /trunk/Quackbot-Plugins/vlc_http
Add /trunk/global-lib/jrebel.jar
```

Yea....

So for questions:

What are some factors for when a commit becomes too large (non-obvious stuff)?

How can you prevent such commits? Please give specifics

What about when your in semi-early stages of development when things are moving quickly? Are huge commits still okay?

答:
There's no hard and fast rule, no dividing line past which your commit is too big.

There is however a guideline that smaller commits are better, within reason (ie committing every line is probaby excessive).

I keep these kinds of guidelines in mind:

A single commit should include changes for just one bug fix

A single commit shouldn't include more than half a days work

A single commit shouldn't break the build

Of course - these are what I keep in mind - YMMV. Different developers favour different levels of granularity.


问:
How to decide which classes are necessary for the system
I know design principles and design patterns in theory. But it's embarrassing to realize that it's not clear when applying it in practice.

For example, let's think about simple tic tac toe console game. How would you decide what class is for certain responsibility and how do you determine that responsibility/class is necessary for the system even before applying design patterns or principles? I understand it should be based on requirements and domain knowledge, but there are lots ways to satisfy the requirements. If I take agile (TDD) approach, there are still many ways to achieve the key requirement by making it testable.

I wish there are many materials (books or web sites) on this but most of them are on theory but rarely on practices. I would appreciate if anybody can refer to such materials with which I can practice the class designs.

答:
There are certainly multiple ways to design a software system.  Some designs are better than others, and some may be equally good. Also, software systems grow and evolve, meaning that a design that is good today may not be so good tomorrow, when a new feature must be added.

Nevertheless there are tried and tested principles and practices that help you to figure out how to decompose your problem into classes, objects, algorithms, patterns, etc.  Remember, writing software is an iterative process, just like writing a book.  You never get it right on the first try.  Instead, you start with a rough draft, and keep refining it.  The two main concepts are cohesion and coupling.  You want your modules to have high cohesion, epitomized by the single responsibility principle, and low coupling.  You also want your design to make sense to other people, so that it can be easily understood, implemented, or augmented.

One good approach is to draw a high-level diagram of your system, e. g. using UML.  If it looks like a mess, or if parts of it do not make sense, you probably want to refactor.  It may also help to explain your system to somebody else.  First, you will likely see design flaws yourself as you talk.  Second if other people find your design hard to follow, you should probably fix it.  Another way is to explain your design in writing.  Then read it.  Does it make sense to you?  Then give it to other people to read.  Does it make sense to them?

Designing software does get easier with experience.  You develop a sense for code smells, which point you to potential design flaws. However, even if you have been writing code for decades, it is still a good idea to explain your designs to other people and see if they can follow your code.

To be more concrete, I highly recommend the following two books: Clean Code by Robert C. Martin, and Refactoring by Martin Fowler.


答:
A solution (that we might be able to test soon enough built-in in VS) is a deep integration within the IDE. the IDE is already able to do all the things you are considering as missing or not working actually :

Syntax awareness

Project hierarchy for file operations

Data structure map for moved code matching

The downside, is that such tool will be binded to the languages supported by the IDE, and as such could limits its universality.

There are already some plug-ins for different IDE available. I didn't tested them, but provide link for examples of existing solutions :

Jupiter - Eclipse (SO Related Question)

TeamReview - TFS / VS

Body:
Why don't many code review tools seem to be syntax aware or provide more in-depth analysis of changes? Is it simply too hard to do?

I find this to be a major hole of most programmer's toolkits. From what I have seen, which admittedly is not much, code review tools just compare code line-by-line with many of them not even being able to do syntax highlighting.

Is there a solution out there that is smart enough to offer file-level, method-level code review/comparison? One of the simple problems I have is that methods get re-ordered in code and my code review software breaks down completely, but they should be able to do so much more.

I'm interested in others opinions/knowledge on the topic of code review/comparison tools.

ContentLicense: CC BY-SA 4.0


问:
What are the drawbacks to the ActiveRecord pattern?
I'm curious what are the drawbacks to using the ActiveRecord pattern for data access/business objects.  The only one I can think of off the top of my head is that it violates the Single Responsibility Principle, but the AR pattern is common enough that this reason alone doesn't seem "good enough" to justify not using it (of course my view may be skewed since often none of the code I work with follows any of the SOLID principles).

Personally I am not a fan of ActiveRecord (with the exception of writing a Ruby on Rails application, where AR feels "natural") because it feels like the class is doing too much, and data access shouldn't be up to the class itself to handle.  I prefer to use Repositories that return business objects.  Most of the code I work with tends to use a variation of ActiveRecord, in the form of (I do not know why the method is a boolean):

```<code>public class Foo
{
    // properties...

    public Foo(int fooID)
    {
        this.fooID = fooID;
    }

    public bool Load()
    {
        // DB stuff here...
        // map DataReader to properties...

        bool returnCode = false;
        if (dr.HasRows)
            returnCode = true;

        return returnCode;
    }
}
</code>```

or sometimes the more "traditional" way of having a public static Foo FindFooByID(int fooID) method for the finders and something along the lines of public void Save() for saving/updating.

I get that ActiveRecord is typically much simpler to implement and use, but it seems a little too simple for complex applications and you could have a more robust architecture by encapsulating your data access logic in a Repository (not to mention having it easier to swap out data access strategies e.g. maybe you use Stored Procs + DataSets and want to switch to LINQ or something)

So what are other drawbacks to this pattern that should be considered when deciding if ActiveRecord is the best candidate for the job?

答:
The biggest drawback to active record is that your domain usually becomes tightly coupled to a particular persistence mechanism. Should that mechanism require a global change, perhaps from file-based to DB-based persistence, or between data access frameworks, EVERY class that implements this pattern may change. Depending on the language, framework, and design, even something so simple as changing where the DB is located or who "owns" it might require going through every object to update the data access methods (this is uncommon in most languages that provide easy access to config files with connection strings).

It also generally requires you to repeat yourself. Most persistence mechanisms have a lot of common code, to connect to a DB and start a transaction. DRY (Don't Repeat Yourself) would tell you as a coder to centralize such logic.

It also makes atomic operations tricky. If a group of objects must be saved in an all-or-nothing fashion (such as an Invoice and its InvoiceLines and/or Customer and/or GL entries), either one object must know about all these other objects and control their persistence (which stretches the scope of the controlling object; large interconnected records can easily become "god objects" that know everything about their dependencies), or the control over the entire transaction must be handled from outside the domain (and in that case why are you using AR?)

It's also "wrong" from an Object-Oriented perspective. In the real world, an invoice doesn't know how to file itself, so why would an Invoice code object know how to save itself to the DB? Of course, overly religious adherence to "objects should only model what their real-world counterparts can do" would lead to anemic domain models (an invoice also doesn't know how to calculate its own total, but splitting the calculation of that total to another object is generally considered a bad idea).


问:
Teaching C++ to first time high school students: Where to draw the line?
I will be mentoring a team of high school students for the FIRST Robotics Competition, most teams here develop[ their robot software using C++. For many of the students on the team this will be their first introduction to programming. I wouldn't have chosen C++ for teaching programming to high schoolers (e.g. Python or Javascript would have been easier I think) but the choice is set.

I want to teach them proper C++ (i.e. avoid a mixed C/C++ dialect, i.e. C+) but I don't want to scare them either with needless complexity. For that matter:

Should I start using STL from day one, esp. vector or just stick with standard arrays? Arrays are easier to introduce but the pointer errors may be harder to catch.

For I/O, should I stick to cout, etc. or do you think printf would be easier to learn?

Are there any online resources for C++ that are suitable to use for such young learners?

Thanks!

EDIT: Thanks for so many excellent answers. In addition to Accelerated C++, which is suggested by many people, I have found that C++ For Everyone is an excellent text.

答:
I would start out with significant chunks of boilerplate code, help them "do something cool" with the programming right away and refine their understanding of how things work over time. They don't need to appreciate or understand all the intricacies of C++ to make an LED blink. They just need to know "if you put this code there, it will make the LED blink." And then "hey, lets talk about what a loop is now, if you write a loop, you can make the LED blink 50 times without having to write 50 lines of code, isn't that cool?" Now lets talk about conditionals, when the user presses button A on the control box, we want to activate the pneumatics to raise a flag, here's how we'd add code to do that. Or if switch 2 on our control box is flipped to on, we run the drill motor in reverse instead of forward. Here's what a conditional statement looks like and how we tell the drill motor which direction to run....

If you keep things focused on teaching them "just enough" to solve the problems they're interested in, it will make things a lot less overwhelming and more approachable. If they're really interested, and want to understand the intricacies, they'll probably go back and read a comprehensive book on programming or taking a summer school course at the local JC.

Make a list of the "things they want to be able to control" on their robot and turn each one into a lesson...what is the least they need to know to... ?

do something "cool looking" if a switch is in a particular setting?

tell a pneumatic valve to open or close (eg: a grabber attachment)?

turn drill motors on and off (for the drivetrain)?

make the robot change directions if an obstacle detection sensor is activated?

make the robot switch between 2 wheel vs 4 wheel drive modes?

adjust the sensitivity of the joystick?

etc.

I would stick to teaching the contructs that are most foolproof, like I would teach cout over printf, because format specifiers are very easy to mix up and an incorrect specifier is often an automatic recipe to crash your program. Likewise, vector obfuscates some of the memory management complexities. Don't worry about every detail about how things work, or what the STL library is, just the least they need to know to accomplish X (which might require using an STL library datastructure, for example)

OwnerDisplayName: recipriversexclusion


问:
When is it necessary to use ORM tools?
I was raised in a part of web developmentland where the creation of websites is mostly synonymous with Wordpress, FTP, Joomla, and procedural code, instead of things like TDD, A/B testing, Doctrine, and design patterns. Having not traveled this area much, I'd like to know when object relational mapping and ORM tools are necessary to create and manage a site. Can you provide some generic (but real world examples) of when it should be used?</p>

答:
Necessary? Never.

ORMs are an layer of abstraction over the database. They are intended as translators between object graphs and database tables/relationships. In this capacity they simplify simple data access and with a large object model/database can save a lot of time otherwise spent writing boilerplate code for data access (getting a record by ID, deleting it by ID, updating and inserting a record).

Useful? Almost always, for the points made above.

There are no rules, as such, but ORMs are best used for basic DB operations (Insert, Update, Delete, Select). When you need something more complex, it is best to use the standard API for your platform.

Title: When is it necessary to use ORM tools?


答:
ORM tools should be used for CRUD, that 80% of code that is so tedious to write over and over, that you want to bang your head against the wall.

Feel free to use more "old school" methods like Stored Procedures for the remaining 20% (e.g. operations that require performance optimization).

For a simple example of how ORMs can be effectively used to create an organized and effective Repository class for retrieving and updating database data CRUD style, see here:

http://nerddinnerbook.s3.amazonaws.com/Part3.htm

Title: When is it necessary to use ORM tools?

Body: I was raised in a part of web developmentland where the creation of websites is mostly synonymous with Wordpress, FTP, Joomla, and procedural code, instead of things like TDD, A/B testing, Doctrine, and design patterns. Having not traveled this area much, I'd like to know when object relational mapping and ORM tools are necessary to create and manage a site. Can you provide some generic (but real world examples) of when it should be used?</p>


答:
There's no "one way" to design a piece of software. There are plenty for each case.

Creating a BDUF (Big design up front) is usually a bad idea, because you either over-design or prepare for things that are never going to be used, or even making future clean implementations impossible, retrospectively.

I recommend starting out with a top-down evolutionary design.
Always keep the next highest-level piece and its immediate collaborators in mind, instantiating classes which do not yet exist as you find necessary in the caller's code, and then implementing those classes once you know that the way your code is implemented truly requires them.

The important thing to remember is that, as you progress, constantly refactor and remove duplication.

Using TDD you can do everything I said and make everything testable.

Title: How to decide which classes are necessary for the system

Body:
I know design principles and design patterns in theory. But it's embarrassing to realize that it's not clear when applying it in practice.

For example, let's think about simple tic tac toe console game. How would you decide what class is for certain responsibility and how do you determine that responsibility/class is necessary for the system even before applying design patterns or principles? I understand it should be based on requirements and domain knowledge, but there are lots ways to satisfy the requirements. If I take agile (TDD) approach, there are still many ways to achieve the key requirement by making it testable.

I wish there are many materials (books or web sites) on this but most of them are on theory but rarely on practices. I would appreciate if anybody can refer to such materials with which I can practice the class designs.


答:
Commit messages should be one line only (and for git max 60 chars).  The amount of code being committed must be small enough to keep the descriptive message within that limit.

I tend to commit everytime (even more so now we've switched to git) I have a chunk done, as it allows to capture the "why" things were done in this way.

Title: When is a version control commit too large?

Body:
I've heard in several places "Don't make large commits" but I've never actually understood whats a "large" commit. Is it large if you work on a bunch of files even if there related? How many parts of a project should you be working on at once?

To me, I have trouble trying to make "small commits" since I forget or create something that creates something else that creates something else. You then end up with stuff like this:

```
Made custom outgoing queue

Bot
-New field msgQueue which is nothing more than a SingleThreadExecutor
-sendMsg blocks until message is sent, and adds wait between when messages get
sent
-adminExist calls updated (see controller)
-Removed calles to sendMessage

Controller
-New field msgWait denotes time to wait between messages
-Starting of service plugins moved to reloadPlugins
-adminExists moved from Server because of Global admins. Checks at the channel,
server, and global level

Admin
-New methods getServer and getChannel that get the appropiate object Admin
belongs to

BotEvent
-toString() also show's extra and extra1

Channel
-channel field renamed to name
-Fixed typo in channel(int)

Server
-Moved adminExists to Controller

PluginExecutor
-Minor testing added, will be removed later

JS Plugins
-Updated to framework changes
-Replaced InstanceTracker.getController() with Controller.instance
-VLC talk now in own file

Various NB project updates and changes

---

Affected files
Modify  /trunk/Quackbot-Core/dist/Quackbot-Core.jar
Modify  /trunk/Quackbot-Core/dist/README.TXT
Modify  /trunk/Quackbot-Core/nbproject/private/private.properties
Modify  /trunk/Quackbot-Core/nbproject/private/private.xml
Modify  /trunk/Quackbot-Core/src/Quackbot/Bot.java
Modify  /trunk/Quackbot-Core/src/Quackbot/Controller.java
Modify  /trunk/Quackbot-Core/src/Quackbot/PluginExecutor.java
Modify  /trunk/Quackbot-Core/src/Quackbot/info/Admin.java
Modify  /trunk/Quackbot-Core/src/Quackbot/info/BotEvent.java
Modify  /trunk/Quackbot-Core/src/Quackbot/info/Channel.java
Modify  /trunk/Quackbot-Core/src/Quackbot/info/Server.java
Modify  /trunk/Quackbot-GUI/dist/Quackbot-GUI.jar
Modify  /trunk/Quackbot-GUI/dist/README.TXT
Modify  /trunk/Quackbot-GUI/dist/lib/Quackbot-Core.jar
Modify  /trunk/Quackbot-GUI/nbproject/private/private.properties
Modify  /trunk/Quackbot-GUI/nbproject/private/private.xml
Modify  /trunk/Quackbot-GUI/src/Quackbot/GUI.java
Modify  /trunk/Quackbot-GUI/src/Quackbot/log/ControlAppender.java
Delete  /trunk/Quackbot-GUI/src/Quackbot/log/WriteOutput.java
Modify  /trunk/Quackbot-Impl/dist/Quackbot-Impl.jar
Modify  /trunk/Quackbot-Impl/dist/README.TXT
Modify  /trunk/Quackbot-Impl/dist/lib/Quackbot-Core.jar
Modify  /trunk/Quackbot-Impl/dist/lib/Quackbot-GUI.jar
Modify  /trunk/Quackbot-Impl/dist/lib/Quackbot-Plugins.jar
Modify  /trunk/Quackbot-Impl/lib/javarebel.stats
Add /trunk/Quackbot-Impl/lib/jrebel.info
Modify  /trunk/Quackbot-Impl/nbproject/private/private.properties
Modify  /trunk/Quackbot-Impl/nbproject/private/private.xml
Modify  /trunk/Quackbot-Impl/nbproject/project.properties
Modify  /trunk/Quackbot-Impl/plugins/CMDs/Admin/reload.js
Add /trunk/Quackbot-Impl/plugins/CMDs/Operator/hostBan
Modify  /trunk/Quackbot-Impl/plugins/CMDs/Operator/mute.js
Modify  /trunk/Quackbot-Impl/plugins/CMDs/lyokofreak/curPlaying.js
Modify  /trunk/Quackbot-Impl/plugins/CMDs/lyokofreak/lfautomode.js
Modify  /trunk/Quackbot-Impl/plugins/listeners/onJoin.js
Modify  /trunk/Quackbot-Impl/plugins/listeners/onQuit.js
Modify  /trunk/Quackbot-Impl/plugins/testCase.js
Add /trunk/Quackbot-Impl/plugins/utils/whatsPlaying.js
Modify  /trunk/Quackbot-Impl/src/Quackbot/impl/SandBox.java
Add /trunk/Quackbot-Impl/vlc_http
Add /trunk/Quackbot-Impl/vlc_http/current.html
Modify  /trunk/Quackbot-Plugins/dist/Quackbot-Plugins.jar
Modify  /trunk/Quackbot-Plugins/dist/README.TXT
Modify  /trunk/Quackbot-Plugins/dist/lib/Quackbot-Core.jar
Modify  /trunk/Quackbot-Plugins/nbproject/private/private.properties
Modify  /trunk/Quackbot-Plugins/nbproject/private/private.xml
Modify  /trunk/Quackbot-Plugins/src/Quackbot/plugins/JSPlugin.java
Add /trunk/Quackbot-Plugins/vlc_http
Add /trunk/global-lib/jrebel.jar
```

Yea....

So for questions:

What are some factors for when a commit becomes too large (non-obvious stuff)?

How can you prevent such commits? Please give specifics

What about when your in semi-early stages of development when things are moving quickly? Are huge commits still okay?


问:
How exactly do Patchers work?
Did a search for Patchers and didn't find anything.
But seriously Patchers: How do they work?

I've done some googling, and i've gotten mixed results. I mean it seems they probably have some way of going in and changing the files (maybe comparing what is different between the files) but it seems like there is probably more going on than that. Or is it really as simple as running a diff. vs another file....and then applying the changes?

答:
Yes, it is really as simple as pie, you can learn it in 10 minutes :)

The (multi-lingual) article shows how to apply patches using the command line tool patch in various scenarios, and how to create patches using the command line tool diff.

Therefore, the article shows that patching is really simply reduced to diffing.

Title: How exactly do Patchers work?


答:
Do you see how many different answers you're getting here?

You know what the conclusion is?

There are no standard, well-known and actually-common names for this kind of thing.

If you want people to understand you, simply call them as they are: data structures and classes (or business rules). If you want to make a clear distinction somewhere, explain it - verbosely.

Sticking to extra-formal terms always seems so unpragmatic to me.


答:
ORM's serve two worthwhile goals;

Abstracting some of the database specific dialect details; and otherwise insulating developers from the weirdness that SQL can sometimes be.

Most ORM's are an 80-20 sort of tool, where they can significantly simplify about 80% of the work of persistence, compared to using SQL directly.  For simple applications, 80% is really 100%, since the platform can often direct the design decisions.

Larger, more complex applications will always have problems that could not have been anticipated by any tool.  The difference between good and bad ORM's shows in sharp relief when this happens.

A good ORM will get out of the way of developers when they need to issue custom SQL to get at their data, or even provide simple extension or introspection mechanisms to grow into the needed use.  Poor ones just get in the way of this sort of thing; requiring developers to do these custom jobs at a lower layer.

Attaching business intelligence or other convenient behaviors to the persistent entities.

Getting the most out of the class mapping features of ORM's often requires a deep understanding on the part of the ORM's developers what role application objects play.  The model objects fulfill a very different role from the persistent state they wrap.

Specifically, the rows and columns in a database represent the set of facts believed true, but the methods and inheritance graphs of the models are the rules and formulae that the application operates on.

When an ORM conflates the two ideas, they'll obstruct developers in a number of idiomatic ways.  There will be no way to operate on relations that aren't part of a table (obvious counterexamples are the rows returned by a select containing joins or group by clauses).  Another breakdown is that they assume that every table must have a primary key; or that the primary key must be an integer or a single column.  A more subtle way ORM's can mess this up is by providing object features, like many-to-many properties, that somehow require a database connection to work properly (the entity relationship is not related to persistence).

Title: When is it necessary to use ORM tools?


问:
How can a maintenance-only programmer get a raise?
I have been working as a maintenance programmer for a couple of years and am wondering if there is such a thing as a raise for maintenance programmer?  I ask because responsibilities don't get wider, you're still doing almost the same things, maybe a little faster as time passes. If it's possible, then what would be the path to get it?</p>

答:
Your rate is what you negotiate when you first interview for a job.  Speaking from personal experience, raises have not netted more money in the same way that new jobs have.

You need to start thinking in terms of labor economics (supply and demand).

When you believe your labor (your education, experience, skills,

what you are able to do) is under-valued:

Look at the market for your particular skill set.

If there's a strong demand (due to a shortage of labor) change jobs.

If there's weak demand, stay in your current job and learn other skill sets (with strong demand) on the side.

While you are trying to assess the labor market for your particular skill-set, you will observe that other skill-sets (experience with particular software packages, programming paradigms, etc) are "in demand".  By "in demand", I mean that there are a lot of jobs posted for those skill sets with rates considerably higher than what you're getting.

This is called doing a labor market survey.

You need to find what the most "in demand" skill sets are.  Make a spreadsheet with the skill sets you encounter on job boards (indeed.com, dice.com, monster.com)

Next to each skill set, list the count of jobs currently advertised (in your local area radius if you're not willing to move).

Go down the list and research each skill set.  You may find that a lot of the skill sets that are "in demand" happen to require proprietary software that you have no access to (i.e. costs lots of money, you need to enroll in an expensive training course).  Write down the investment required (time and money) for you to acquire each skill set in your skill-set "market survey" spreadsheet.

You may want to avoid skill sets requiring an unreasonable investment.

Find the best skill sets (most jobs, best rates, least investment on your part) and go about learning these on your own while keeping your current job.

Then apply for jobs and interview.  You can schedule multiple interviews during vacation days.  Be prepared to drive a lot, be prepared to be thoroughly grilled on the newly learned skill set and be prepared for rejection.  Don't give up.

If you do get a new job after interviewing, you will have a good bargaining position with your current employer.

You can start thinking of your current employer as your "client #2" and your new employer as your "client #1"

Ask for a raise at your current job to match the hourly rate you negotiated for at the new job.  Be polite but strong.  If they nix the raise (the rule, not the exception) politely give 2 weeks' notice.  You may get called in for an exit interview.  Explain your position and let them know that you are happy to do maintenance work on the side/part-time, at your new hourly rate.

If they ask you back full time for more money than your new job, politely refuse their offer.  More often than not, this is their ploy to get you to stay long enough to train your replacement.

Again, be polite but strong.  Do not explode.  Do not burn bridges.  Client #2 may still need you and you can make some nice money forking for them part time or telecommuting for a while.

Keep repeating the above recipe until you feel that you have "topped out".  You "top out" when you no longer have more money to gain from learning a new skill set.

Be prepared to work long hours and to negotiate a lot.  Your clients (#2,#3,#4,#5,...) will have a lot of work for you to do.

P.S.: Never train your replacement.

The worst self-inflicted injury technical people make is training their replacement.

What it boils down to is that you need to apply market rules to your situation.


答:
If your application is using a relational database, your code will contain a lot of SQL (or LINQ if you are using .NET).

The ideas is to simplify interacton between application code and the database by creating Data Access Layer and business objects quickly and without coding, yet allows the developer to extend the logic by adding special business rules (if any).

Object Relational Mapping tools are many. Not all tools are the same. Some are simple whereas some are complex enough to be an entire framework.

They rely on database already built (tables) and read the table definitions from your database then:

0-Creates classes that represent objects (usually 1 to 1), such classes contain methods to read, write, update and delete data from the database. Some support LINQ (.Net) and some have their own object query language.

1-Handle primary key generation and table to table relationships automatically

2-Can read and return data related to a table automatically with one method call

3-Allow you to switch the database without coding

4-Take care of data buffering to enhance performance

5-Generate necessary SQL to get and put data to database automatically

6-Some generate web services automatically (e.g. Oxygen)

7-Some can generate auditing code for you automatically

8-Some can create stored procedures

9-Some provide authorization support

10-Some support multiple tier architecture automatically

11-Some support .NET Entity Framework

So if you need any of the above services in your project, ORM may be for you.

It may be something for you to decide whether you want to use ORM or Entity Framework if you are a .NET user.

Title: When is it necessary to use ORM tools?


答: Don't ask for a raise.  Ask for more responsibility.  The raise will follow.</p>

Title: How can a maintenance-only programmer get a raise?

Body: I have been working as a maintenance programmer for a couple of years and am wondering if there is such a thing as a raise for maintenance programmer?  I ask because responsibilities don't get wider, you're still doing almost the same things, maybe a little faster as time passes. If it's possible, then what would be the path to get it?</p>


问:
How do you decide between putting the code in the database or putting the code in the application?
For the sake of argument:

Let's assume the application we are building is an amortization schedule.

Let's also assume that the database has a table called tblAmortizationPayments that stores the information about each monthly payment in a separate row.

Let's further assume that the database language can support the math calculations needed to perform the calculations.

If you were to build this amortization schedule for a 30 year mortgage, how would you decide between placing the code for performing these 360 calculations inside the database (I'm assuming this would be a stored procedure) or inside the application?

I'm more interested in your thought process for making this type of decision or any similar scenario that might come along.

答:
It is always advisable to keep database logic inside the database. The reason is because the abstraction of the details of the underlying datastore should be made opaque to the application.

If the database structure changes,  you will want to alter stored procs, functions, and views.  But you don't want the application to break from any minor to most major database changes.

The database engine, through the use of stored procedures, also caches execution plans even if the paramter values change.

Logic separation should be separated as much as possible, and that's all part of n-tier architecture.

Leave database logic to the database.


答:
You will get two schools of thought: Stored Procedures and No Stored Procedures.  I'm in the camp that the database is just for holding my data, my program is for analyzing and using that data.  With the advent of the Entity Framework, it pushes more of the emphasis on the code side (in my opinion).

If using Stored Procedures, then you have TWO places to look for a potential bug: your code, and/or your Stored Procedure.

Title: How do you decide between putting the code in the database or putting the code in the application?

Body:
For the sake of argument:

Let's assume the application we are building is an amortization schedule.

Let's also assume that the database has a table called tblAmortizationPayments that stores the information about each monthly payment in a separate row.

Let's further assume that the database language can support the math calculations needed to perform the calculations.

If you were to build this amortization schedule for a 30 year mortgage, how would you decide between placing the code for performing these 360 calculations inside the database (I'm assuming this would be a stored procedure) or inside the application?

I'm more interested in your thought process for making this type of decision or any similar scenario that might come along.


问:
What's your favourite quote about programming?
What's your favourite quote about programming?

One quote per answer, and please check for duplicates before posting!

答:
Every time I ask developers why their shiny new C# .NET version isn't nearly as fast and smooth as the old C/C++ version, I'm thinking of:

The most amazing achievement of the computer software industry is its continuing cancellation of the steady and staggering gains made by the computer hardware industry.

    — Henry Petroski

But they just tell me to shut up while they plaster on yet another level of abstraction...

LastEditorDisplayName: Roger Pate


答:
The main factors to my mind:

Does the developer that will program this have more proficiency in the language of the database or the language of the application?

How loaded is the database server compared to the server running the application?

How much code is currently existing in either form?

If the DB server is getting used so heavily that it may time out in running the stored procedure then it may be better to do it in the application.  Similarly, if the developer has extensive experience in one over the other then either may make sense as it could be used to build up skills in the weaker side or leverage the stronger side depending on which way one wants to value the upside of each option.


问:
What was the worst piece of code you fixed that you are proud of?
I have had a few that I am proud of and some of them were written by myself few years ago. It doesn't have to be necessarily buggy, just bad code. </p>

答:
I think nothing even comes close to this:

```<code>function pmn_Sort(strBy)

local tblA = {};
local tblB = {};
local tblC = {};
local tblD = {};
local tblE = {};
local tblF = {};
local tblG = {};
local tblH = {};
local tblI = {};
local tblJ = {};
local tblK = {};
local tblL = {};
local tblM = {};
local tblN = {};
local tblO = {};
local tblP = {};
local tblQ = {};
local tblR = {};
local tblS = {};
local tblT = {};
local tblU = {};
local tblV = {};
local tblW = {};
local tblX = {};
local tblY = {};
local tblZ = {};
local tblOT = {};

local iA = 0;
local iB = 0;
local iC = 0;
local iD = 0;
local iE = 0;
local iF = 0;
local iG = 0;
local iH = 0;
local iI = 0;
local iJ = 0;
local iK = 0;
local iL = 0;
local iM = 0;
local iN = 0;
local iO = 0;
local iP = 0;
local iQ = 0;
local iR = 0;
local iS = 0;
local iT = 0;
local iU = 0;
local iV = 0;
local iW = 0;
local iX = 0;
local iY = 0;
local iZ = 0;
local iOT = 0;

    if strBy == "Name" then

        strSort = "Name";
        numPlcount = ListBox.GetCount("Playlist");
        numPLitem = 1;
        numPLadd = 0;
        while numPLitem <= numPlcount do

            strPLtxt = ListBox.GetItemText("Playlist", numPLitem);
            strPLdata = ListBox.GetItemData("Playlist", numPLitem);
            strPLleft = String.Left(strPLtxt, 1);
            if strPLleft == "a" or strPLleft == "A" then

            iA = iA + 1;
            tblA[iA] = strPLdata;

            elseif strPLleft == "b" or strPLleft == "B" then

            iB = iB + 1;
            tblB[iB] = strPLdata;

            elseif strPLleft == "c" or strPLleft == "C" then

            iC = iC + 1;
            tblC[iC] = strPLdata;

            elseif strPLleft == "d" or strPLleft == "D" then

            iD = iD + 1;
            tblD[iD] = strPLdata;

            elseif strPLleft == "e" or strPLleft == "E" then

            iE = iE + 1;
            tblE[iE] = strPLdata;

            elseif strPLleft == "f" or strPLleft == "F" then

            iF = iF + 1;
            tblF[iF] = strPLdata;

            elseif strPLleft == "g" or strPLleft == "G" then

            iG = iG + 1;
            tblG[iG] = strPLdata;

            elseif strPLleft == "h" or strPLleft == "H" then

            iH = iH + 1;
            tblH[iH] = strPLdata;

            elseif strPLleft == "i" or strPLleft == "I" then

            iI = iI + 1;
            tblI[iI] = strPLdata;

            elseif strPLleft == "j" or strPLleft == "J" then

            iJ = iJ + 1;
            tblJ[iJ] = strPLdata;

            elseif strPLleft == "k" or strPLleft == "K" then

            iK = iK + 1;
            tblK[iK] = strPLdata;

            elseif strPLleft == "l" or strPLleft == "L" then

            iL = iL + 1;
            tblL[iL] = strPLdata;

            elseif strPLleft == "m" or strPLleft == "M" then

            iM = iM + 1;
            tblM[iM] = strPLdata;

            elseif strPLleft == "n" or strPLleft == "N" then

            iN = iN + 1;
            tblN[iN] = strPLdata;

            elseif strPLleft == "o" or strPLleft == "O" then

            iO = iO + 1;
            tblO[iO] = strPLdata;

            elseif strPLleft == "p" or strPLleft == "P" then

            iP = iP + 1;
            tblP[iP] = strPLdata;

            elseif strPLleft == "q" or strPLleft == "Q" then

            iQ = iQ + 1;
            tblQ[iQ] = strPLdata;

            elseif strPLleft == "r" or strPLleft == "R" then

            iR = iR + 1;
            tblR[iR] = strPLdata;

            elseif strPLleft == "s" or strPLleft == "S" then

            iS = iS + 1;
            tblS[iS] = strPLdata;

            elseif strPLleft == "t" or strPLleft == "T" then

            iT = iT + 1;
            tblT[iT] = strPLdata;

            elseif strPLleft == "u" or strPLleft == "U" then

            iU = iU + 1;
            tblU[iU] = strPLdata;

            elseif strPLleft == "v" or strPLleft == "V" then

            iV = iV + 1;
            tblV[iV] = strPLdata;

            elseif strPLleft == "w" or strPLleft == "W" then

            iW = iW + 1;
            tblW[iW] = strPLdata;

            elseif strPLleft == "x" or strPLleft == "X" then

            iX = iX + 1;
            tblX[iX] = strPLdata;

            elseif strPLleft == "y" or strPLleft == "Y" then

            iY = iY + 1;
            tblY[iY] = strPLdata;

            elseif strPLleft == "z" or strPLleft == "Z" then

            iZ = iZ + 1;
            tblZ[iZ] = strPLdata;

            else

            iOT = iOT + 1;
            tblOT[iOT] = strPLdata;

            end

            numPLitem = numPLitem + 1;

        end

        ListBox.DeleteItem("Playlist", LB_ALLITEMS);

        for ii, id in tblA do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblB do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblC do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblD do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblE do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblF do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblG do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblH do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblI do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblJ do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblK do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblL do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblM do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblN do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblO do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblP do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblQ do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblR do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblS do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblT do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblU do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblV do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblW do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblX do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblY do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblZ do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblOT do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

    elseif strBy == "Type" then

        strSort = "Type";

        if File.DoesExist(_ProgramFilesFolder.."\\MediaX\\playlist.mx") == true then

            play_file2 = TextFile.ReadToTable(_ProgramFilesFolder.."\\MediaX\\playlist.mx");

            if play_file2 then
                ListBox.DeleteItem("Playlist", -1);

                for rl,rPath in play_file2 do
                    r2Path = String.TrimLeft(rPath, nil);
                    ListBox.AddItem("Playlist", String.SplitPath(r2Path).Filename..String.SplitPath(r2Path).Extension, r2Path);
                end
            end
        end
    end
end
</code>```

The fix? Eh, that shouldn't require much explanation.

Body:
I think nothing even comes close to this:

function pmn_Sort(strBy)

local tblA = {};
local tblB = {};
local tblC = {};
local tblD = {};
local tblE = {};
local tblF = {};
local tblG = {};
local tblH = {};
local tblI = {};
local tblJ = {};
local tblK = {};
local tblL = {};
local tblM = {};
local tblN = {};
local tblO = {};
local tblP = {};
local tblQ = {};
local tblR = {};
local tblS = {};
local tblT = {};
local tblU = {};
local tblV = {};
local tblW = {};
local tblX = {};
local tblY = {};
local tblZ = {};
local tblOT = {};

local iA = 0;
local iB = 0;
local iC = 0;
local iD = 0;
local iE = 0;
local iF = 0;
local iG = 0;
local iH = 0;
local iI = 0;
local iJ = 0;
local iK = 0;
local iL = 0;
local iM = 0;
local iN = 0;
local iO = 0;
local iP = 0;
local iQ = 0;
local iR = 0;
local iS = 0;
local iT = 0;
local iU = 0;
local iV = 0;
local iW = 0;
local iX = 0;
local iY = 0;
local iZ = 0;
local iOT = 0;

    if strBy == "Name" then

        strSort = "Name";
        numPlcount = ListBox.GetCount("Playlist");
        numPLitem = 1;
        numPLadd = 0;
        while numPLitem &lt;= numPlcount do

            strPLtxt = ListBox.GetItemText("Playlist", numPLitem);
            strPLdata = ListBox.GetItemData("Playlist", numPLitem);
            strPLleft = String.Left(strPLtxt, 1);
            if strPLleft == "a" or strPLleft == "A" then

            iA = iA + 1;
            tblA[iA] = strPLdata;

            elseif strPLleft == "b" or strPLleft == "B" then

            iB = iB + 1;
            tblB[iB] = strPLdata;

            elseif strPLleft == "c" or strPLleft == "C" then

            iC = iC + 1;
            tblC[iC] = strPLdata;

            elseif strPLleft == "d" or strPLleft == "D" then

            iD = iD + 1;
            tblD[iD] = strPLdata;

            elseif strPLleft == "e" or strPLleft == "E" then

            iE = iE + 1;
            tblE[iE] = strPLdata;

            elseif strPLleft == "f" or strPLleft == "F" then

            iF = iF + 1;
            tblF[iF] = strPLdata;

            elseif strPLleft == "g" or strPLleft == "G" then

            iG = iG + 1;
            tblG[iG] = strPLdata;

            elseif strPLleft == "h" or strPLleft == "H" then

            iH = iH + 1;
            tblH[iH] = strPLdata;

            elseif strPLleft == "i" or strPLleft == "I" then

            iI = iI + 1;
            tblI[iI] = strPLdata;

            elseif strPLleft == "j" or strPLleft == "J" then

            iJ = iJ + 1;
            tblJ[iJ] = strPLdata;

            elseif strPLleft == "k" or strPLleft == "K" then

            iK = iK + 1;
            tblK[iK] = strPLdata;

            elseif strPLleft == "l" or strPLleft == "L" then

            iL = iL + 1;
            tblL[iL] = strPLdata;

            elseif strPLleft == "m" or strPLleft == "M" then

            iM = iM + 1;
            tblM[iM] = strPLdata;

            elseif strPLleft == "n" or strPLleft == "N" then

            iN = iN + 1;
            tblN[iN] = strPLdata;

            elseif strPLleft == "o" or strPLleft == "O" then

            iO = iO + 1;
            tblO[iO] = strPLdata;

            elseif strPLleft == "p" or strPLleft == "P" then

            iP = iP + 1;
            tblP[iP] = strPLdata;

            elseif strPLleft == "q" or strPLleft == "Q" then

            iQ = iQ + 1;
            tblQ[iQ] = strPLdata;

            elseif strPLleft == "r" or strPLleft == "R" then

            iR = iR + 1;
            tblR[iR] = strPLdata;

            elseif strPLleft == "s" or strPLleft == "S" then

            iS = iS + 1;
            tblS[iS] = strPLdata;

            elseif strPLleft == "t" or strPLleft == "T" then

            iT = iT + 1;
            tblT[iT] = strPLdata;

            elseif strPLleft == "u" or strPLleft == "U" then

            iU = iU + 1;
            tblU[iU] = strPLdata;

            elseif strPLleft == "v" or strPLleft == "V" then

            iV = iV + 1;
            tblV[iV] = strPLdata;

            elseif strPLleft == "w" or strPLleft == "W" then

            iW = iW + 1;
            tblW[iW] = strPLdata;

            elseif strPLleft == "x" or strPLleft == "X" then

            iX = iX + 1;
            tblX[iX] = strPLdata;

            elseif strPLleft == "y" or strPLleft == "Y" then

            iY = iY + 1;
            tblY[iY] = strPLdata;

            elseif strPLleft == "z" or strPLleft == "Z" then

            iZ = iZ + 1;
            tblZ[iZ] = strPLdata;

            else

            iOT = iOT + 1;
            tblOT[iOT] = strPLdata;

            end

            numPLitem = numPLitem + 1;

        end

        ListBox.DeleteItem("Playlist", LB_ALLITEMS);

        for ii, id in tblA do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblB do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblC do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblD do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblE do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblF do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblG do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblH do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblI do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblJ do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblK do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblL do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblM do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblN do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblO do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblP do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblQ do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblR do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblS do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblT do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblU do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblV do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblW do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblX do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblY do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblZ do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

        for ii, id in tblOT do

            if id ~= "" then

                numPLadd = numPLadd + 1;
                strPLtxt = String.SplitPath(id).Filename..String.SplitPath(id).Extension
                ListBox.AddItem("Playlist", strPLtxt, id);

            end

        end

    elseif strBy == "Type" then

        strSort = "Type";

        if File.DoesExist(_ProgramFilesFolder.."\\MediaX\\playlist.mx") == true then

            play_file2 = TextFile.ReadToTable(_ProgramFilesFolder.."\\MediaX\\playlist.mx");

            if play_file2 then
                ListBox.DeleteItem("Playlist", -1);

                for rl,rPath in play_file2 do
                    r2Path = String.TrimLeft(rPath, nil);
                    ListBox.AddItem("Playlist", String.SplitPath(r2Path).Filename..String.SplitPath(r2Path).Extension, r2Path);
                end
            end
        end
    end
end

The fix? Eh, that shouldn't require much explanation.


答:
There are two competing philosophies here:

If you place all of the business logic for calculating the payments in the application, then any further application needs that come along (desktop, web, smartphone, changing platforms, web service, other databases, etc.) need to have that code duplicated. We struggle with that now at my work with two applications that access the same databases, do some of the same things, and yet don't always rely on streamlined database code.

If you have the database do the calculations, then it only needs to be done in one place. Any application can connect to the database, call the stored procedure and get the same results. You'll never have two execs arguing that their reports are giving the right numbers, or someone's house getting foreclosed on because one app shows they've been shorting their payments and another shows they've been overpaying.

My opinion is that the business logic should be done as much as possible in the database, but if you can't then make sure you only put it in one place and not split it between the database and the application.


答:
The problem with putting the code inside the database is that the database's programming language isn't very good, relative to what you write the business logic in.  Lets say that after a while you want to support multiple types of amortizations based on the type of contract, and that some contracts are based on variable rates calculated as formulas defined differently by individual contract with variables in the rate formulas referencing rate tables such as LIBOR.  Now imagine multiple currencies are thrown in.  Now imagine some contracts calculate interest on the first business day of the month based on the holiday calendar of the country the contract is written in ...

Obviously, YAGNI will probably cover all my examples, but the point is that there are lots of business requirements that might make you want to move business logic out of the database and into a more powerful language.  Of course, you could apply YAGNI and keep it in a stored procedure now, but there is a higher chance that it will move to the business layer than there is of it moving to the database if it starts out in the business layer, as a general rule.

This is the kind of thing that can be a tough call, but it's something to keep in mind in your particular case.


问:
Are there any languages built to facilitate implementing design patterns?
Often it is not obvious how to implement a given design pattern in a language. Sometimes it is difficult or cumbersome. Are there any languages built to make using design patterns easy and effective?</p>

答:
The important thing is that a design pattern isn’t intrinsic to a language; it’s quite literally just a code pattern at which many developers have independently arrived. The design patterns that emerge in a particular language are considered the idiomatic, preferred way of solving certain kinds of problems.

Sure, there are countless MVC “frameworks” out there, but they’re really just using MVC as a label for the underlying good practice—modularity and orthogonality between data model, presentation, and user interaction.

A language cannot be designed to make “using design patterns” easy and effective, because design patterns emerge from the design of the language. You cannot design a language around patterns that will appear as a result of its own strengths and deficiencies. All you can do is design a more expressive and powerful one. If the popular idioms and patterns for a given language are cumbersome to implement, it simply means that the language itself is cumbersome.

Tautologically: in a more expressive language, it’s easier to express yourself.


答:
There is no right answer for this.

Stored Procedures will be easier to update if there is a bug, just update the procedure, no need to do a code build.  With code a build would be required if there is a bug.

If you ever change your backend data (Oracle to SQl Server or vice versa), the code will need to be ported over, with code the logic stays intact and can be ported, provided platform remain the same.

With code, it should be easier and less complex to design an extendable amortization scheduler.  If the calculations change from client, extensibility would be design goals.  Stored procedures are somewhat monolithic, so code would be a better choice.   With a stored procedure I could see it becoming messy if different types of calculations are required.

If the business says the calcuation is the same no matter what, I would lean toward a stored procedure, if there could be future differences, I'd put it in code and make it extensible.


问:
How can I advocate unit testing on private code?
I'm trying to advocate unit testing in my workgroup, but an objection I often get is that it should be used only for externally exported API (which is only a minimal and non critical part of our system), and not on internal and private code (which now has only functional testing).

While I think that unit test can and should be applied to all the code, how can I persuade my coworkers?

答:
If you mean private the way I think you mean it, then no - you shouldn't be unit testing it. You should only be unit testing observable behaviour/state. You may be missing the point behind the "red-green-refactor" cycle of TDD (and if you're not doing test first then the same principle apply). Once the tests are written and passing you do not want them to be changing whilst performing the refactoring. If you're forced to unit test private functionality then it probably means that the unit tests around the public functionality are flawed. If it's difficult and complex to write tests around the public code then maybe your class is doing too much or your problem isn't clearly defined.

Worse, over time your unit tests will become a ball and chain slowing you down without adding any value whatsoever (changing implementation, for example optimisation or removal of duplication, should have no effect on the unit tests). Internal code should, however, be unit tested as the behaviour/state is observable (just in a restricted way).

When I first did unit testing I pulled all sorts of tricks to unit test private stuff but now, with a few years under my belt, I see it as worse than a waste of time.

Here's a bit of a silly example, of course in real life you would have more tests than these:

Let's say you have a class that returns a sorted list of strings - you should check that the result is sorted, not how it actually sorts that list. You could start your implementation with a single algorithm that just sorts the list. Once that's done your test doesn't need to change if you then change your sorting algorithm. At this point you have a single test (assuming that the sorting is embedded in your class):

Is my result sorted?

Now say you want two algorithms (perhaps one is more efficient in some circumstances but not others), then each algorith could (and generally, should) be provided by a different class and your class picks from them - you can check this is happening for your chosen scenarios using mocks, but your original test is still valid and as we are only verifying observable behaviour/state it doesn't need to change. You end up with 3 tests:

Is my result sorted?

Given a scenario (let's say the initial list is almost sorted to begin with) is a call made to the class that sorts strings using algorithm X?

Given a scenario (the initial list is in a random order) is a call made to the class that sorts strings using algorithm Y?

The alternative would have been to begin testing private code inside your class - you don't gain anything from this - the above tests tell me everything that I need to know as far as unit testing is concerned. By adding private tests you're building yourself a straight jacket, how much more work would it be if you not only checked that the result was sorted but also how it's sorted?

Tests (of this type) should only change when behaviour changes, start writing tests against private code and that goes out the window.


问:
Is it useful to learn CVS before learning SVN?
Is it useful to learn CVS before learning SVN? Does much of that knowledge carry over to SVN or are they too different?</p>

答: Both CVS and SVN are centralized version control systems. Having existing knowledge of workflows and using one will help you use the other, but learning CVS first simply to use SVN wouldn't add any value. If you are interested in a centralized version control system or your team is using SVN, just jump right into SVN. Documentation and tutorials abound on the Internet.</p>


答:
No.
Learning CVS is not useful and it will rot your brain and teach you bad habits.
Recall that CVS is basically a wrapper for RCS which is about as poor as SCCS.
SVN replaces all the functionality of CVS and removes the limitations.

It's kind of like asking if you should learn Visual Basic before learning Javascript.  Yuck, why would anyone bother.

The better bet is to learn SVN and also learn one other system which is decentralized such as mercurial or git.

Body: Is it useful to learn CVS before learning SVN? Does much of that knowledge carry over to SVN or are they too different?</p>


问:
terminology: Memory leak
When I hear the term memory leak by that I mean a bug in a program that doesn't cause any problems except that it doesn't free memory resource and if it continuously does that it can eat a lot of memory, hurting system performance and in the worst case crash the program (or an other program, if the OS decides to choose to kill that one).

But now in this comments section of this question the upvotes made me think whether that's the whole meaning of the term. I previously always saw used it in that meaning.

https://stackoverflow.com/questions/7451437/is-this-a-mem-leak-in-main

So, would you call something a simple memory leak that crashes a program by some other side-effect or causing a dead-lock by not freeing a lock?

Update - Note: unfortunately some admin deleted the comment section there so I cannot refer to that discussion anymore :/

Basically I said that a memory leak is harmless except that it eats up memory (and consequently on the long term in that respect can be harmful, crashing the app/system). They said that's not true, with C++ RAII it can cause serious problems. - Yes, if you don't delete an object with some important code in the destructor that can cause problems, but in my vocabulary that's a major bug and not a memory leak.

答:
http://en.wikipedia.org/wiki/Memory_leak#Consequences

would you call something a simple memory leak that crashes a program by some other side-effect

Memory leaks can cause random bugs since memory may be assigned unexpected values.

causing a dead-lock by not freeing a lock?

Dead locks can be caused by memory which has been assigned unexpected values.

Further reading on this topic:

http://en.wikipedia.org/wiki/Memory_pool

http://en.wikipedia.org/wiki/Stack_overflow

Title: terminology: Memory leak


答:
The quintessential memory leak would be exactly what you described, the failure to free some memory the process had allocated. The consequences would normally be that the program gradually grows in size while it's running, with possible secondary effects due to that. Subsequent memory allocations might fail or the system might misbehave due to the wasted resources.

However, a problem can be accurately described as a memory leak so long as it does in fact leak memory. It can also do other things that are potentially more serious. For example, if you fail to close a standard I/O stream, that's a memory leak because memory associated with the stream will be leaked. However, it can also run the process out of file descriptors or perhaps cause a subsequent stream open to fail because of a limit on the number of standard I/O streams.

Title: terminology: Memory leak

Body:
When I hear the term memory leak by that I mean a bug in a program that doesn't cause any problems except that it doesn't free memory resource and if it continuously does that it can eat a lot of memory, hurting system performance and in the worst case crash the program (or an other program, if the OS decides to choose to kill that one).

But now in this comments section of this question the upvotes made me think whether that's the whole meaning of the term. I previously always saw used it in that meaning.

https://stackoverflow.com/questions/7451437/is-this-a-mem-leak-in-main

So, would you call something a simple memory leak that crashes a program by some other side-effect or causing a dead-lock by not freeing a lock?

Update - Note: unfortunately some admin deleted the comment section there so I cannot refer to that discussion anymore :/

Basically I said that a memory leak is harmless except that it eats up memory (and consequently on the long term in that respect can be harmful, crashing the app/system). They said that's not true, with C++ RAII it can cause serious problems. - Yes, if you don't delete an object with some important code in the destructor that can cause problems, but in my vocabulary that's a major bug and not a memory leak.


答:
Patchers vary in complexity. But the basic idea is that they follow a three-step process:

Identify what is already present.

Formulate a plan to convert that to the desired result.

Execute that plan.

In the simplest form of patcher, one file is replaced by another. The existing file is usually identified by a checksum or hash to ensure that the patch should be applied. Then the old file is replaced with the new file, often stored in the patch file in compressed form.

More sophisticated patchers can analyze the existing file(s) and recognize versions that it can update to the version it patches to. They can then used 'diff' files that efficiently describe the difference between two files.

Some patchers can even build a checksum of all the files present on the system and then upload them to a central site which can then create a 'diff' specifically for that combination. Files recognized from previous versions will trigger a 'diff' for that file to be included in the package. Files not recognized (or those for which a compressed 'diff' is not available) will result in the entire new file being downloaded.

But the basic process is simple, remove the old, install the new.

Title: How exactly do Patchers work?

Body:
Did a search for Patchers and didn't find anything.
But seriously Patchers: How do they work?

I've done some googling, and i've gotten mixed results. I mean it seems they probably have some way of going in and changing the files (maybe comparing what is different between the files) but it seems like there is probably more going on than that. Or is it really as simple as running a diff. vs another file....and then applying the changes?


答: A related meaning of "memory leak" applies to languages that use garbage collection.  There, memory is supposed to be leaked, but if you fail to do so, it's the same problem.

Title: terminology: Memory leak


答:
Imagine that the client asked to have a particular change made - for example to add a rule that something or another can't be done within two days of the "whatever" date. Then, after you've made the change, they change their minds. You will want to roll back your commit. If it's all mushed in with some things about changing the sort order of unrelated reports, your life is a misery.

One work item, one changeset. One request from the client, one changeset. One thing you might change your mind about, one changeset. Sometimes that means it is one single line of code. Sometimes it is ten different files including the database schema. That's fine.


答:
It depends.  Certainly the program could have crashed because of a memory leak. But I wouldn't call all crashes memory leaks.  A memory leak has a very clear definition.

An application crash could be caused many different things.

Unhandled Exception

Memory Leak

Resource Leak

Deadlock

Other (bug in code)

At the time of the crash one would have to take a crash/memory dump and use something like Windbg to analyze the state of the code at the time of the crash to determine if it was a memory leak, deadlock, bug, etc.

A memory leak is simply not freeing memory after you are finished with it.  This can cause a crash if the resource limits are met as you have noted.

A resource leak is not freeing the resource after you are done with it.  An example could be opening a database connection and not closing it after you are finished.

Deadlocks are different than leaks, because leaks can go undetected and could be benign if system resources are not consumed. Deadlocks are a condition which do not build up over time.

Title: terminology: Memory leak


答:
Why fix an old bug if you can write three new ones in the same time?

— David Kastrup

Body:
What's your favourite quote about programming?

One quote per answer, and please check for duplicates before posting!