答:
They are functions, they just follow slightly different rules.  The "functions" are often targets and rules for building.  Another way to think about out it is the nodes and lines in the build DAG.  The "targets" are the nodes or build artifacts and the lines are the rules on how to transform the previous nodes.

I approach refactoring build scripts first by figuring out what the DAG is. Then isolating the common rules and de-duplicate.

Here is a simplistic example:

```<code>all:
   mkdir bigfiles
   cat file1 file2 > bigfiles/bigfile1
   cat file3 file4 > bigfiles/bigfile2
</code>```

What the DAG should be:

```<code>file1 \
        =-> bigfile1 \
file2 /               \
                        =-> all
file3 \               /
        =-> bigfile2 /
file4 /
</code>```

New Rules:

```<code> bigfiles:
   mkdir bigfiles

 bigfiles/bigfile1: bigfiles
   cat file1 file2 > bigfiles/bigfile1

 bigfiles/bigfiles2: bigfiles
   cat file3 file4 > bigfiles/bigfile2
</code>```

De-duplicated:

```<code> BIGFILES:=bigfiles/bigfile1 bigfiles/bigfile2
 bigfiles/bigfile1:=file1 file2
 bigfiles/bigfile2:=file3 file4

 .PHONY: all
 all: $(BIGFILES)

 bigfiles:
    mkdir bigfiles

 $(BIGFILES): bigfiles
    cat $($@) > $@
</code>```

At the end of this exercise I currently have slightly more code than I started with.  HOWEVER, You also have a more generic "function".  A "function" that has been properly parametrized and is thus more maintainable and extensible as a result.

Title: What are good ways to organize input files (Makefiles, SConstruct, CMakeLists.txt, etc.) to build automation software?

Body:
One thing I like to do with my code is make sure that it's refactored into manageable pieces. However, when it comes to building the software, I find that whatever build automation software I end up using (lately it's been GNU Make or SCons) ends up becoming a complete mess. The input files look like long scripts that seem to defy easy refactoring. I'd like to be able to refactor them in some way, but the concept of "function" doesn't quite behave the same way in some build automation software as it does in a programming language, so I find it difficult to write manageable Makefiles or SConscript files for any projects that are moderately complicated.

Does anyone have any advice on writing manageable input files for build automation software? Software-agnostic advice would be best, but even advice about a specific build automation tool would be helpful, particularly Make or SCons, since that's what I've been using for projects.

Edit: As Thorbjørn has pointed out, I should add some context and usage examples. I'm finishing up my PhD in chemical engineering and I do research in computational science. (I'm a pro tem mod over at SciComp.SE, for those of you who visit.) My projects typically involve a mix of compiled languages (C, C++, Fortran) that do some of the heavy lifting, scripting languages (Python, Perl) for prototyping, and occasionally, domain-specific languages for prototyping or technical purposes.

I've added two examples below, roughly in the 250-line range. The problem for me is generally a lack of modularity. Some of these projects can be organized into modular units, and it'd be nice to abstract the parts of the build along those lines to make it easier for me and future maintainers to keep track of. Breaking each script up into multiple files has been one solution I've been toying around with in my head.

The second example is particularly important, because I'm going to have to a large number of files to it soon.

Here's what a 265-line Makefile might look like for me, taken from an actual project, and organized as best I can:

#!/usr/bin/make
#Directory containing DAEPACK library folder
daepack_root = .
library = $(daepack_root)/lib
wrappers = $(daepack_root)/Wrappers/DSL48S
c_headers = parser.h problemSizes.h
f77_headers=problemSizes.f commonParam.f
f90_headers=problemSizes.f commonParam.f90
includes = -I. -Iinclude -I/usr/include/glib-2.0 \
    -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 \
    -I/usr/include/libgdome -I/usr/include/gtest/

#Fortran 77 environment variables
f77=gfortran
fflags=-ggdb -cpp -fno-second-underscore --coverage -falign-commons \
    -mcmodel=large -fbacktrace -pg
flibs=

#Fortran 90 environment variables
f90=gfortran
f90flags=-ggdb -cpp -fno-second-underscore --coverage -falign-commons \
    -mcmodel=large -fbacktrace -pg
f90libs=

#C environment flags
cc=gcc
cflags=-ggdb --coverage $(includes) -mcmodel=large
clibs=

#Libraries for linking
libs=-L$(library) -ldaepack_sparse -lblas -llapack -ldl -lg2c \
    -lgdome -lxml2 -lgtest -lcunit -lcholmod -lamd -lcolamd -lccolamd \
    -lmetis -lspqr -lm -lblas -llapack -lstdc++ -lpcre

#Object files
objs=main.o $(dsl48sObjs) $(gdxObjs)
gdxObjs = gdxf9def.o gdxf9glu.o gamsglobals_mod.o
commonObjs=libdsl48s_model.sl cklib.o parser.o $(gdxObjs)
originalModelObjs=originalModel.o dsl48sChemkinModule.o $(commonObjs)
cspSlowModelObjs=cspSlowModel.o dsl48sChemkinModuleSlow.o cspModule.o \
    $(commonObjs)
orthoProjModelObjs=orthoProjModel.o dsl48sChemkinModuleOrthoProj.o \
    orthoProjModule.o basisModule.o spqrUtility.o $(commonObjs)

#Shell environment variable definitions for FUnit
FCFLAGS := $(f90flags)
LDFLAGS := libdsl48s_model.sl cklib.o gdxf9glu.o parser.o spqrUtility.o \
    $(libs)

misc=*table *size.f
output=*.out

#Ftncheck flags for static analysis of Fortran 77 code
ftnchekflags= -declare -include=. -library -style=block-if,distinct-do,do-enddo,end-name,goto,labeled-stmt,structured-end

all: ckinterp.exe parserTest.exe originalModel.exe cspSlowModel.exe \
    orthoProjModel.exe spqrUtilityTest.exe
#Check code style with lexical analyzer
    @echo Checking program style...
    ftnchek $(ftnchekflags) rhs.f
    ftnchek $(ftnchekflags) resorig.f
    ftnchek $(ftnchekflags) res.f
#   ftnchek $(ftnchekflags) cklib.f
#   ftnchek $(ftnchekflags) ckinterp.f
#Set up baseline coverage data file
    @echo Set up baseline coverage data file
    lcov -c -i -d . -o conpDSL48Sbase.info
#Run unit test on cspModule.f90
    @echo Running unit tests on cspModule.f90...
    funit cspModule
#Generate test coverage data for cspModule.f90
    @echo Generating test coverage data from cspModule.f90 tests...
    lcov -c -d . -o conpDSL48ScspTest.info
#Run unit test on orthoProjModule.f90
    @echo Running unit tests on orthoProjModule.f90...
    funit orthoProjModule
#Generate test coverage data for orthoProjModule.f90
    @echo Generating test coverage data from orthoProjModule.f90 tests...
    lcov -c -d . -o conpDSL48SgenProjTest.info
#Run unit tests on the parser C library
    @echo Running unit tests on parser in C...
    -G_SLICE=always-malloc G_DEBUG=gc-friendly valgrind -v --tool=memcheck \
    --leak-check=full --show-reachable=yes --leak-resolution=high \
    --num-callers=20 --log-file=parserTest.vgdump \
    ./parserTest.exe > parserTest.log
#Generate test coverage data for the parser wrapper C library
    @echo Generating test coverage data for the parser in C...
    lcov -c -d . -o conpDSL48SparserTest.info
#Run unit tests on the SparseQR C library
    @echo Running unit tests on SparseQR library in C...
    ./spqrUtilityTest.exe
#Generate test coverage data for the SparseQR C library
    @echo Generating test coverage data for the SparseQR C library...
    lcov -c -d . -o conpDSL48SsparseTest.info
#Run unit test on basisModule.f90
    @echo Running unit tests on basisModule.f90...
    funit basisModule
#Generate test coverage data for basisModule.f90
    @echo Generating test coverage data from basisModule.f90 tests...
    lcov -c -d . -o conpDSL48SbasisMod.info
#Combine test coverage data
    @echo Combine baseline and test coverage data...
    lcov -a conpDSL48Sbase.info \
    -a conpDSL48ScspTest.info \
    -a conpDSL48SgenProjTest.info \
    -a conpDSL48SbasisMod.info \
    -a conpDSL48SparserTest.info \
    -a conpDSL48SsparseTest.info \
    -o conpDSL48Stotal.info
#Post-process to remove coverage statistics from automatically
#generated source code.
    @echo Removing coverage statistics for automatically generated source...
    lcov -r conpDSL48Stotal.info basisModule_fun.f90 \
    ckinterp.f cklib.f cspModule_fun.f90 davisSkodjeAd.f90 \
    davisSkodjeJac.f90 davisSkodjeRes.f90 davisSkodjeRhs.f90 \
    davisSkodjeSp.f90 gdxf9def.f90 gdxf9glu.c orthoProjModule_fun.f90 \
    jac.f jacorig.f resad.f resadp.f resorigad.f resorigadp.f ressp.f \
    resorigsp.f senrhs.f senrhsorig.f TestRunner.f90 \
    -o conpDSL48Stotal.info
#Generate HTML report of coverage data
    @echo Generate HTML report of coverage data...
    genhtml conpDSL48Stotal.info
    @echo Open "index.html" in browser for coverage results!

originalModel.exe: $(originalModelObjs) $(f90_headers) $(f77_headers) \
    $(c_headers)
    $(f90) $(f90flags) -o originalModel.exe $(originalModelObjs) $(libs)

originalModel.o: dsl48sChemkinModule.o $(commonObjs) $(f77_headers) \
    $(f90_headers) $(c_headers)
    $(f90) $(f90flags) -c -o originalModel.o originalModel.f90

cspSlowModel.exe: $(cspSlowModelObjs) $(f90_headers) $(f77_headers) \
    $(c_headers)
    $(f90) $(f90flags) -o cspSlowModel.exe $(cspSlowModelObjs) $(libs)

cspSlowModel.o: dsl48sChemkinModuleSlow.o cspModule.o $(commonObjs) \
    $(c_headers) $(f77_headers)
    $(f90) $(f90flags) -c -o cspSlowModel.o cspSlowModel.f90

orthoProjModel.exe: $(orthoProjModelObjs) $(f90_headers) $(f77_headers) \
    $(c_headers) resOrthoFast.o
    $(f90) $(f90flags) -o orthoProjModel.exe $(orthoProjModelObjs) \
    resOrthoFast.o $(libs)

orthoProjModel.o: dsl48sChemkinModuleOrthoProj.o orthoProjModule.o $(commonObjs) \
    $(c_headers) $(f90_headers) $(f77_headers) resOrthoFast.o basisModule.o
    $(f90) $(f90flags) -c -o orthoProjModel.o orthoProjModel.f90

dsl48sChemkinModule.o: dsl48sChemkinModule.f90 cklib.o problemSizes.h \
    parser.o $(c_headers) $(f90_headers)
    $(f90) $(f90flags) -c -o dsl48sChemkinModule.o dsl48sChemkinModule.f90

dsl48sChemkinModuleSlow.o: dsl48sChemkinModuleSlow.f90 cspModule.o cklib.o \
    problemSizes.h parser.o $(c_headers) $(f90_headers)
    $(f90) $(f90flags) -c -o dsl48sChemkinModuleSlow.o \
    dsl48sChemkinModuleSlow.f90

dsl48sChemkinModuleOrthoProj.o: dsl48sChemkinModuleOrthoProj.f90 \
    orthoProjModule.o basisModule.o cklib.o problemSizes.h \
    parser.o $(c_headers) $(f90_headers)
    $(f90) $(f90flags) -c -o dsl48sChemkinModuleOrthoProj.o \
    dsl48sChemkinModuleOrthoProj.f90

basisModule.o: basisModule.f90 cklib.o spqrUtility.o commonParam.f90
    $(f90) $(f90flags) -c -o basisModule.o basisModule.f90

spqrUtility.o: spqrUtility.h spqrUtility.c
    $(cc) $(cflags) -c -o spqrUtility.o spqrUtility.c

spqrUtilityTest.exe: spqrUtilityTest.o spqrUtility.o
    $(cc) $(cflags) -o spqrUtilityTest.exe spqrUtilityTest.o \
    spqrUtility.o $(libs)

spqrUtilityTest.o: spqrUtilityTest.c spqrUtility.o
    $(cc) $(cflags) -c -o spqrUtilityTest.o spqrUtilityTest.c

cklib.o: cklib.f ckstrt.f
    $(f77) $(fflags) -c -o cklib.o cklib.f

ckinterp.exe: ckinterp.o
    $(f77) $(fflags) -o ckinterp.exe ckinterp.o

ckinterp.o: ckinterp.f
    $(f77) $(fflags) -c -o ckinterp.o ckinterp.f

#Recursive makefile inherited from previous graduate students
libdsl48s_model.sl: $(f77_headers) cklibDAEPACK.f
    cp $(wrappers)/makefile model.mk
    make -f model.mk

resOrthoFast.o: libdsl48s_model.sl
    $(f90) $(f90flags) -c -o resOrthoFast.o resOrthoFast.f90

problemSizes.f: problemSizes.fpp problemSizes.h
    cpp problemSizes.fpp problemSizes.f
    perl -p -i.bak -we 's/# /! /;' problemSizes.f

commonParam.f90: commonParam.f
    perl -p -i.bak -we 's/^#/!/;' commonParam.f
    echo "commonParam t f t fpp" | pref77tof90
    echo "commonParam /" | f77tof90
    perl -p -i.bak -we 's/integer a/!integer a/;' commonParam.f
    perl -p -i.bak -we 's/END   //;' commonParam.f90

commonParam.f: commonParam.fpp problemSizes.h
    cpp commonParam.fpp commonParam.f
    perl -p -i.bak -we 's/^#/!/;' commonParam.f

cspModule.o: cspModule.f90
    $(f90) $(f90flags) -c -o cspModule.o cspModule.f90

orthoProjModule.o: gamsglobals_mod.o gdxf9def.o gdxf9glu.o orthoProjModule.f90 \
    formatLabels.f90
    $(f90) $(f90flags) -c -o orthoProjModule.o orthoProjModule.f90

gdxf9def.o: gdxf9def.f90
    $(f90) $(f90flags) -c -o gdxf9def.o gdxf9def.f90

gdxf9glu.o: gdxf9glu.c gdxf9def.o
#64-bit version of wrappers (with underscores)
    $(cc) $(cflags) -DCIA_LEX -DAPIWRAP_LCASE_DECOR -c -o \
    gdxf9glu.o gdxf9glu.c
#64-bit version of wrappers (without underscores, for C interoperability)
#   $(cc) $(cflags) -DCIA_LEX -DAPIWRAP_LCASE_NODECOR -c gdxf9glu.c
#32-bit version of wrappers
#   $(cc) $(cflags) -DAPIWRAP_LCASE_DECOR -c gdxf9glu.c -Iinclude

gamsglobals_mod.o: gamsglobals_mod.f90 gdxf9def.o gdxf9glu.o
    $(f90) $(f90flags) -c gamsglobals_mod.f90

parser.o: parser.c $(c_headers)
    $(cc) $(cflags) -c -o parser.o parser.c

parserTest.exe: parserTest.o parser.o
    $(cc) $(cflags) -o parserTest.exe parser.o \
    parserTest.o $(libs)

parserTest.o: parserTest.cpp parser.o
    $(cc) $(cflags) -c -o parserTest.o parserTest.cpp

clean:
    -rm *.bak
    -rm *.f77
    -rm *.log
    -rm commonParam.f90
    -rm problemSizes.f
    -rm commonParam.f
    -make clean -f model.mk
    -rm model.mk
    -rm *.o
    -rm *.mod
    -rm $(misc)
    -rm *.exe
    -funit --clean
    -rm *.gcno
    -rm *.gcda
    -rm *.info
    -rm *.png
    -rm *.html
    -rm *.css
    -rm -rf html
    -rm *.pyc
    -rm *.lst
```

<p>Here's a 245-line <code>SConstruct</code> file that I'm currently trying to organize for a project that's roughly as complex:</p>

<pre class="lang-py prettyprint-override"><code>## \file SConstruct
#  \brief Compiles the library and compiles tests.
#

import SCons

## \brief Build up directory names of each COIN library from package names
#         and versions.
#

## Overall SCons environment
#
env = Environment();

flags = []

## Compile using debug versions?
#
debug = True
debugString = '-debug'
debugFlags = ['-ggdb']

dynamicLinkFlag = '-Wl,-rpath,'

if debug:
    flags += debugFlags

## Compile Google Test from scratch.
#
GTestVersion = '1.6.0'
GTestStem = 'gtest-' + GTestVersion
GTestBuildIncDir = [GTestStem,
                    GTestStem + '/include',
                    ]
GTestAllLib = env.Library('lib/libgtest.a', 'gtest-1.6.0/src/gtest-all.cc',
                      CPPPATH = GTestBuildIncDir,
                      CXXFLAGS = flags)
GTestMainLib = env.Library('lib/libgtest_main.a',
                           'gtest-1.6.0/src/gtest_main.cc',
                           CPPPATH = GTestBuildIncDir,
                           CXXFLAGS = flags)

GTestIncDir = GTestStem + '/include/gtest'
GTestLibDir = 'lib'
GTestLibFlags = ['gtest', 'gtest_main', 'pthread']

## Armadillo matrix library
#
ArmadilloLibFlags = ['armadillo'];

## Quick reminder of SCons flags:
#  CPPPATH = path of headers (include directories)
#  LIBPATH = path of libraries
#  LIBS = flags of libraries
#  CXXFLAGS = C++ compilation flags
#

## Locations of libraries installed on system in standard locations
#
StdIncDir = '/usr/include'
StdLibDir = '/usr/lib'

## Configuration information for COIN libraries
#
CoinUtilsVersion = '2.6.4'
ClpVersion = '1.12.0'
OsiVersion = '0.103.0'
CbcVersion = '2.5.0'

## Some standard directory locations of COIN libraries, with slashes added for
#  for convenience.
#
CoinLibLocation = '/usr/local/COIN/'
StdCoinIncDir = '/include/coin'
StdCoinLibDir = '/lib'

CoinUtilsStem = 'CoinUtils-' + CoinUtilsVersion
ClpStem = 'Clp-' + ClpVersion
OsiStem = 'Osi-' + OsiVersion
CbcStem = 'Cbc-' + CbcVersion

if debug:
    CoinUtilsStem += debugString
    CbcStem += debugString
    ClpStem += debugString
    OsiStem += debugString

## Build up include directory names for COIN projects from constituent parts.
#
CoinUtilsIncDir = CoinLibLocation + CoinUtilsStem + StdCoinIncDir
ClpIncDir = CoinLibLocation + ClpStem + StdCoinIncDir
OsiIncDir = CoinLibLocation + OsiStem + StdCoinIncDir
CbcIncDir = CoinLibLocation + CbcStem + StdCoinIncDir

## Build up library names from COIN projects from constituent parts
#
CoinUtilsLibDir = CoinLibLocation + CoinUtilsStem + StdCoinLibDir
ClpLibDir = CoinLibLocation + ClpStem + StdCoinLibDir
OsiLibDir = CoinLibLocation + OsiStem + StdCoinLibDir
CbcLibDir = CoinLibLocation + CbcStem + StdCoinLibDir

## CPLEX
#
CpxStem = '/opt/ibm/ILOG/CPLEX_Studio_Academic123/cplex/'
CpxIncDir = CpxStem + 'include/ilcplex'
CpxLibDir = CpxStem + 'lib/x86-64_sles10_4.1/static_pic'

## Gurobi
#
GrbStem = '/opt/gurobi460/linux64/'
GrbIncDir = GrbStem + 'include'
GrbLibDir = GrbStem + 'lib'

OsiLibFlags = ['Osi', 'CoinUtils']
ClpLibFlags = ['Clp', 'OsiClp']
CbcLibFlags = ['Cbc', 'Cgl']
OsiCpxLibFlags = ['OsiCpx']
OsiGrbLibFlags = ['OsiGrb']
CpxLibFlags = ['cplex', 'ilocplex', 'pthread', 'm']
GrbLibFlags = ['gurobi_c++', 'gurobi46', 'pthread', 'm']

milpIncDirs = [CoinUtilsIncDir,
               ClpIncDir,
               OsiIncDir,
               CbcIncDir,
               CpxIncDir,
               GrbIncDir,
            GTestIncDir,
               ]
milpLibDirs = [CoinUtilsLibDir,
               ClpLibDir,
               OsiLibDir,
               CbcLibDir,
               CpxLibDir,
               GrbLibDir,
               GTestLibDir,
            ]
milpLibFlags = [OsiCpxLibFlags,
                OsiGrbLibFlags,
                CbcLibFlags,
                ClpLibFlags,
                OsiLibFlags,
                CpxLibFlags,
                GrbLibFlags,
                GTestLibFlags,
                ]
##milpSolver = env.Object('milpSolver.cpp',
            ##                         CPPPATH = milpIncDirs,
##                         LIBPATH = milpLibDirs,
##                         CXXFLAGS = flags)
milpSolverTest = env.Program('milpSolverUnitTest',
                                  ['milpSolverTest.cpp',
                                   'milpSolver.cpp'],
                                  CPPPATH = milpIncDirs,
                                  LIBPATH = milpLibDirs,
                                  LIBS = milpLibFlags,
                                  CXXFLAGS = flags,
                                  LINKFLAGS = ['-Wl,-rpath,' + OsiLibDir])
env.Depends(milpSolverTest, [GTestAllLib, GTestMainLib])

## Chemkin source directories and files
#
ChemkinSourceDir = '/mnt/hgfs/DataFromOldLaptop/Data/ModelReductionResearch/Papers/AdaptiveChemistryPaper/AdaptiveChemistry/NonOpenSource/ChemkinII/';
ChemkinSourceList = ['cklib.f', 'pcmach.f','tranlib.f']
ChemkinSourceList = [ChemkinSourceDir + FileName
                     for FileName in ChemkinSourceList]
env.Depends('cklib.f','ckstrt.f')

## Cantera include directorie
#
CanteraStem = '/usr/local/cantera'

if debug:
    CanteraStem += debugString

CanteraIncDir = CanteraStem + '/include/cantera'
CanteraLibDir = CanteraStem + '/lib'
CanteraTestingFlags = ['kinetics', 'thermo', 'tpx', 'ctbase', 'm',]
CanteraLibFlags = ['user', 'oneD', 'zeroD', 'equil', 'kinetics', 'transport',
                    'thermo', 'ctnumerics', 'ctmath', 'tpx', 'ctspectra',
                    'converters', 'ctbase', 'cvode', 'ctlapack', 'ctblas',
                    'ctf2c', 'ctcxx', 'ctf2c', 'm', 'm', 'stdc++']

CxxFortranFlags = ['g2c', 'gfortran'];

chemSolverIncDir = [CanteraIncDir,
                    StdIncDir,
                    '/usr/local/include',
                    GTestIncDir,
                    ]
chemSolverLibDir = [StdLibDir,
                    CanteraLibDir,
                    GTestLibDir,
                    ]
chemSolverLibFlags = [GTestLibFlags,
                      CxxFortranFlags,
                      CanteraLibFlags,
                      ArmadilloLibFlags,
                      ]

chemSolverTest = env.Program('chemSolverUnitTest',
                        ['chemSolverTest.cpp',
                         'chemSolver.cpp',
                         'ckwrapper.f90'] + ChemkinSourceList,
                        CPPPATH = chemSolverIncDir,
                        LIBPATH = chemSolverLibDir,
                        LIBS = chemSolverLibFlags,
                        CXXFLAGS = flags,
                        FORTRANFLAGS = flags,
                        F90FLAGS = flags)
env.Depends(chemSolverTest, [GTestAllLib, GTestMainLib])

#env.AddPostAction(milpSolverTest, milpSolverTest[0].abspath)
testAlias = env.Alias('test', [milpSolverTest, chemSolverTest])
AlwaysBuild(testAlias)

ckInterp = env.Program('ckinterp', ChemkinSourceDir + 'ckinterp.f')

canteraGTestLibFlags = CanteraTestingFlags + GTestLibFlags

#canteraGTestLibFlags = ['kinetics', 'thermo', 'tpx',
#                        'ctbase',  'm', 'gtest', 'gtest_main', 'pthread']

canteraGTest = env.Program('canteraGTest',
                           'canteraGTest.cpp',
                           CPPPATH = chemSolverIncDir,
                           LIBPATH = chemSolverLibDir,
                           LIBS = canteraGTestLibFlags,
                           CXXFLAGS = flags)
env.Depends(canteraGTest, [GTestAllLib, GTestMainLib])

canteraMemTestLibFlags = CanteraTestingFlags

canteraMemTest = env.Program('canteraMemTest',
                             'canteraMemTest.cpp',
                             CPPPATH = chemSolverIncDir,
                             LIBPATH = chemSolverLibDir,
                             LIBS = canteraMemTestLibFlags,
                             CXXFLAGS = flags)
</code>```

Body:
They are functions, they just follow slightly different rules.  The "functions" are often targets and rules for building.  Another way to think about out it is the nodes and lines in the build DAG.  The "targets" are the nodes or build artifacts and the lines are the rules on how to transform the previous nodes.

I approach refactoring build scripts first by figuring out what the DAG is. Then isolating the common rules and de-duplicate.

Here is a simplistic example:

all:
   mkdir bigfiles
   cat file1 file2 > bigfiles/bigfile1
   cat file3 file4 > bigfiles/bigfile2

What the DAG should be:

file1 \
        =-> bigfile1 \
file2 /               \
                        =-> all
file3 \               /
        =-> bigfile2 /
file4 /

New Rules:

 bigfiles:
   mkdir bigfiles

 bigfiles/bigfile1: bigfiles
   cat file1 file2 > bigfiles/bigfile1

 bigfiles/bigfiles2: bigfiles
   cat file3 file4 > bigfiles/bigfile2

De-duplicated:

 BIGFILES:=bigfiles/bigfile1 bigfiles/bigfile2
 bigfiles/bigfile1:=file1 file2
 bigfiles/bigfile2:=file3 file4

 .PHONY: all
 all: $(BIGFILES)

 bigfiles:
    mkdir bigfiles

 $(BIGFILES): bigfiles
    cat $($@) > $@

At the end of this exercise I currently have slightly more code than I started with.  HOWEVER, You also have a more generic "function".  A "function" that has been properly parametrized and is thus more maintainable and extensible as a result.


问:
std::shared_ptr as a last resort?
I was just watching the "Going Native 2012" streams and I noticed the discussion about std::shared_ptr. I was a bit surprised to hear Bjarne's somewhat negative view on std::shared_ptr and his comment that it should be used as a "last resort" when an object's life-time is uncertain (which I believe, according to him, should infrequently be the case).

Would anyone care to explain this in a bit more depth? How can we program without std::shared_ptr and still manage object life-times in a safe way?

答:
I'll try to answer the question:

How can we program without std::shared_ptr and still manage object lifetimes in safe way?

C++ has large number of different ways to do memory, for example:

Use struct A { MyStruct s1,s2; }; instead of shared_ptr in class scope. This is only for advanced programmers because it requires that you understand how dependencies work, and requires ability to control dependencies enough to restrict them to a tree. Order of classes in header file is important aspect of this. It seems this usage is already common with native builtin c++ types, but it's use with programmer-defined classes seems to be less used because of these dependency and order of classes problems. This solution also have problems with sizeof. Programmers see problems in this as a requirement to use forward declarations or unnecessary #includes and thus many programmers will fall back to inferior solution of pointers and later to shared_ptr.

Use MyClass &find_obj(int i); + clone() instead of shared_ptr<MyClass> create_obj(int i);. Many programmers want to create factories for creating new objects. shared_ptr is ideally suited for this kind of usage. The problem is that it already assumes complex memory management solution using heap/free store allocation, instead of simpler stack or object based solution. Good C++ class hierarchy supports all memory management schemes, not just one of them. The reference based solution can work if the returned object is stored inside the containing object, instead of using local function scope variable. Passing ownership from factory to user code should be avoided. Copying the object after using find_obj() is good way to handle it -- normal copy-constructors and normal constructor (of different class) with refrerence parameter or clone() for polymorphic objects can handle it.

Use of references instead of pointers or shared_ptrs. Every c++ class has constructors, and each reference data member needs to be initialized. This usage can avoid many uses of pointers and shared_ptrs. You just need to choose if your memory is inside the object, or outside of it, and choose the struct solution or reference solution based on the decision. Problems with this solution are usually related to avoiding constructor parameters which is common but problematic practise and misunderstanding how interfaces for classes should be designed.

OwnerDisplayName: ronag

ContentLicense: CC BY-SA 3.0

Title: std::shared_ptr as a last resort?


问:
Is there any reason why most programming languages don't have '!>' (not greater than) and '!<' (not less than) operators?
I wonder if there is any reason - or if it is just an accident of history - that there are no !> and !< operators in most programming languages?

a >= b (a greater OR equals b) could be written as !(a < b) (a NOT lesser b), that equals a !< b.

This question struck me when I was in the middle of coding my own expression tree builder. Most programming languages have a != b operator for !(a=b), so why no !> and !< ?

UPDATE:

!< (not lesser) is easier to pronounce than >= (greater or equals)

!< (not lesser) is shorter to type than >= (greater or equals)

!< (not lesser) is easier to understand* than >= (greater or equals)

*because OR is binary operator you brain need to operate two operands (grater, equals), while NOT is unary operator and you brain need to operate only with one operand (lesser).

答:
The D programming language and DMC's extension to C and C++ did support these operators (all 14 combinations of them), but interestingly, D is going to deprecate these operators, mainly because

what exactly is a !< b? It is a>=b || isNaN(a) || isNaN(b). !< is not the same as >=, because NaN !< NaN is true while NaN >= NaN is false. IEEE 754 is hard to master, so using a !< b to will just cause confusion over NaN handling — you can search for such operators in Phobos (D's standard library), and quite a number of use has comments beside it to remind the readers NaN is involved,

therefore, few people will use it, even if such operators exist like in D,

and one have to define 8 more tokens for these seldomly used operators, which complicates the compiler for little benefit,

and without those operators, one could still use the equivalent !(a < b), or if one likes to be explicit, a >= b || isNaN(a) || isNaN(b), and they are easier to read.

Besides, the relations (≮, ≯, ≰, ≱) are seldomly seen in basic math, unlike != (≠) or >= (≥), so it's hard to understand for many people.

These are probably also the reasons why most languages do not support them.


问:
What's wrong with mutability and can it be desirable?

Possible Duplicate:

  At what point do immutable classes become a burden?

This is something I never understood. When learning C++, for instance, I had lots of headaches with const issues, as it added lots of complexity to programming. Why is immutability important? And is it always necessary?

答:
The glib answer is that mutability is necessary, because software that doesn't change anything is kind of pointless.  Ultimately, at least some of your data is going to be mutable - even if it is just the input and output of the process.

Really, though, you are asking why you would choose to use immutable rather than mutable data in various parts of your program, and the answer to that is complexity.

Complexity is the thing that makes software difficult.  Mutable data is inherently complex, because it can change.

Complexity is what makes software difficult, because it makes doing anything with it hard.  It could be the complexity of doing the right thing in the face of all your state, or the complexity of concurrency, or the complexity of changing code to meet new requirements.

Ultimately, though, the simpler software is the easier it is to keep working, and to improve, over time.  There is a lot of education, experience, and related discussion that most of the cost of software is really keeping it working over the full life of the software.

The reason that mutable data makes software more complex is fairly simple, if you contrast the thinking you need to do about the data:

If the data is immutable you need to know what it means, where it was first assigned, and perhaps how it is used here.

If the data is mutable you need to know what it means, where it was first assigned, where it can be changed, when it can be changed, if those changes can happen concurrently and require locks, what sequence locks need to be acquired in, if changing the data needs coordination with others, and if it is actually changed here.

There are other advantages to immutable data, such as garbage collection efficiency, lock-free operation, efficient substructure sharing, and so forth, but they are technical choices - and while they are becoming more important as multi-core processing becomes more common, they are not the heart of the advantage.

Finally, to the implicit question of why you found it so challenging in your learning the language...  Obviously, I can only speculate, but in my experience there are two causes for this in people learning programming, programming languages, and programming paradigms:

The first is that most teaching problems are great tools for learning, but have very little to do with the "real world" of software engineering.  At the scale of a teaching problem you probably know the entire codebase, end to end, and it is small enough you can hold a picture in your head of how it all works.

When you are working with a team of five, or ten, or fifty, or five hundred people on a codebase with a half million lines of code, where you have never even seen most of the code around what you are working on - well, then you start to appreciate immutable data, because you need to know so much less.

The second is that your comment on "added lots of complexity" mirrors what a bunch of other people have said to me.  Generally, they felt it added a lot of complexity because they just wanted to write code until something worked without spending a lot of time thinking about the bigger picture of the problem.

Now, I have no idea if this is true of you or not - I never met you - but maybe it is the same thing.

Mutable data is an easy solution to "I need X to change so that Y happens" when you are in a random part of the code and need to trigger some distant effect.

That adds complexity.  Not local complexity, sure, because you can more easily change the value and all.  Remote complexity.  Invisible complexity.

It spreads out the details of where change happens, and of where the behaviour of the system is defined.  As you go down this path, and grow the size of the system, you rediscover the problems that Object Oriented analysis and design came about to combat.

Again, I don't know you, and that may have nothing to do with why you found it "added complexity", but it is the most common pattern in my experience of folks saying the same thing.


答:
The argument is that immutable data has 2 advantages:

You can safely access it from 2 threads without worrying about locks or other concurrency issues.

In many cases it produces code that's easier to reason about, easier to test, and easier to be confident about its correctness.

For instance, the result of some function might be an object, and perhaps one of the post-conditions we want to test is the value of some property of the result object:

```<code>[Test]
public void Result_of_Foo_has_property_X_which_is_based_on_input_Y()
{
    var test = BuildObjectForTest();
    var result = test.Foo(23);
    Assert.AreEqual(15, result.X);
}
</code>```

If the result object is mutable, then maybe testing property X changed the value of X, or changed some other property of the object.  That's a side-effect, and we try to reduce side effects because they produce complex code.  Also, depending on the internal state of the test object, perhaps calling Foo again with the same argument might not produce the same result.  Programmers using this code need to know that.

If the programmer using it knows that both are immutable objects, they can greatly reduce the amount of thought they have to put into understanding it.

In my experience, there are two types of code: ones that carry out an action (print something to the screen, move the robot, update a record in the database, etc.) and there is code that answers a question.  The first kind obviously has side effects because it kind of changes stuff in the real world (the stuff on the screen is replaced by new stuff, or the robot moves, or the database data is modified).  The second kind should be purely functional, which is side-effect free.  If I ask you to tell me what 2 + 2 is, you shouldn't have to change the value of 2 to tell me the answer is 4.  Therefore, I expect that the values 2 and 4 are immutable.  Likewise, I want my values a and b to be immutable, if I ask you the result of a + b.

Title: What's wrong with mutability and can it be desirable?

Body:
Possible Duplicate:

  At what point do immutable classes become a burden?

This is something I never understood. When learning C++, for instance, I had lots of headaches with const issues, as it added lots of complexity to programming. Why is immutability important? And is it always necessary?

Body:
The argument is that immutable data has 2 advantages:

You can safely access it from 2 threads without worrying about locks or other concurrency issues.

In many cases it produces code that's easier to reason about, easier to test, and easier to be confident about its correctness.

For instance, the result of some function might be an object, and perhaps one of the post-conditions we want to test is the value of some property of the result object:

[Test]
public void Result_of_Foo_has_property_X_which_is_based_on_input_Y()
{
    var test = BuildObjectForTest();
    var result = test.Foo(23);
    Assert.AreEqual(15, result.X);
}

If the result object is mutable, then maybe testing property X changed the value of X, or changed some other property of the object.  That's a side-effect, and we try to reduce side effects because they produce complex code.  Also, depending on the internal state of the test object, perhaps calling Foo again with the same argument might not produce the same result.  Programmers using this code need to know that.

If the programmer using it knows that both are immutable objects, they can greatly reduce the amount of thought they have to put into understanding it.

In my experience, there are two types of code: ones that carry out an action (print something to the screen, move the robot, update a record in the database, etc.) and there is code that answers a question.  The first kind obviously has side effects because it kind of changes stuff in the real world (the stuff on the screen is replaced by new stuff, or the robot moves, or the database data is modified).  The second kind should be purely functional, which is side-effect free.  If I ask you to tell me what 2 + 2 is, you shouldn't have to change the value of 2 to tell me the answer is 4.  Therefore, I expect that the values 2 and 4 are immutable.  Likewise, I want my values a and b to be immutable, if I ask you the result of a + b.


问:
How do I preview my mobile web application on a Windows 7 PC?
I am developing a mobile web application that may be browsed in an iPhone. I would like to test this application, but I lack a mobile web device.

How can I test this mobile application on a Windows 7 PC?

答:
That is tricky. There aren't any emulators, even the one avaliable on OS X is a bad feel for browsing with a touch screen device. You can at least make sure your site renders using something like browsercam.

The best bet is to get an iOS device. iPod Touches make very good approximate iPhones, especially for web apps.


问:
Do big software companies develop their business process management solutions (ERP) in-house?
I was looking at the customer list of a few ERP vendors like SAP. The companies in the list are mostly non IT companies. So, I'm wondering as to how IT companies approach the business process management problem.

For example, any IT company with a few thousand employees across different locations will need software for HR management, accounting, and so on. And a software product vendor (like Microsoft) will need CRM software.

It looks like buying enterprise software from an outside vendor can be a messy and expensive proposition, especially when they can code it in-house using their excellent grasp on the requirements specific to their business.

Do these companies usually build their own solutions using in-house resources or do they buy it from other software vendors?

答:
I think most of them do use the "normal" ERP solutions such as SAP and the like. There may be several reasons for why they are not listed:

They don't want to give that information away to the wrong people.

They may be a competitor of SAP or one of the other ERP vendors.

They don't see the value in being listed.

And probably many more.

You mentioned Microsoft in the question. Microsoft has their own solutions to ERP and CRM. For ERP they have stuff like Dynamics AX and Dynamics NAV, and for CRM they have Dynamics CRM. They probably use some of that stuff themselves, which also gives them valuable information about usage and annoyances in the software.


问:
Handling Errors In PHP When Using MVC
I've been using Codeigniter a lot recently, but one thing that gets on my nerves is handling errors and displaying them to the user. I've never been good at handling errors without it getting messy. My main concern is when returning errors to the user.

Is it good practice to use exceptions and throw/catch exceptions rather than returning 0 or 1 from functions and then using if/else to handle the errors. Thus, making it easier to inform the user about the issue.

I tend to go away from exceptions. My Java tutor at university some years ago told me "exceptions shouldn't be used in production code it's more for debugging". I get the feeling he was lying.

But, an example, I have code that adds a user to a database. During the process more than 1 thing could go wrong, such as a database issue, a duplicate entry, a server issue, etc. When an issue happens during registration the user needs to know about it.

What's the best way to handle errors in PHP, keeping in mind that I'm using an MVC framework.

答:
Is it good practice to use exceptions and throw/catch exceptions rather than returning 0 or 1 from functions and then using if/else to handle the errors. Thus, making it easier to inform the user about the issue.

No, no, no!

Don't mix exceptions and errors. Exceptions are, well, exceptional. Errors are not. When you ask a user to enter a quantity of a product, and the user enters "hello", it's an error. It's not an exception: there is nothing exceptional in seeing an invalid input from the user. Why can't you use exceptions in non-exceptional cases, like when validating input? Other people explained it already, and shown a valid alternative for input validation.

This also means that the user don't care about your exceptions, and showing the exceptions is both unfriendly and dangerous. For example, an exception during an execution of an SQL query often reveals the query itself. Are you sure you want to take a risk to show such message to everyone?

more than 1 thing could go wrong, such as a database issue, a duplicate entry, a server issue, etc. When an issue happens during registration the user needs to know about it.

Wrong. As a user, I don't need to know your database issues, duplicate entries, etc. I really don't care about your problems. What I do need to know is that I entered a username which already exist. As already said, a wrong input from me must trigger an error, not an exception.

How to output those errors? It depends on the context. For an already used username, I would like to see a small red flag appearing near the username, before even submitting the form, saying that the username is already used. With no JavaScript, the same flag must appear after submission.

For other errors, you would show a full page with an error, or choose another way to inform the user that something went wrong (for example a message which will appear, then fade away at the top of the page). The question is then related more to user experience than to programming.

From programmers point of view, depending of the type of the error, you will propagate it in different ways. For example, in a case of a username already taken, an AJAX request to http://example.com/?ajax=1&user-exists=John will return a JSON object indicating:

That the user already exists,

The error message to show to the user.

The second point is important: you want to be sure that the same message appear both when submitting the form with JavaScript disabled and typing a duplicate username with JavaScript enabled. You don't want to duplicate the text of the error message in server-side source code and in JavaScript!

This is actually the technique used by Stack Exhange websites. For example if I try to upvote my own answer, the AJAX response contains the error to display:

```<code>{"Success":false,"Warning":false,"NewScore":0,"Message":"You can't vote for your own post.",
"Refresh":false}
</code>```

You can also choose another approach, and preset the errors in the HTML page before the form is filled. Pros: you don't have to send the error message in AJAX response. Cons: what about accessibility? Try to browse the page without CSS, and you'll see all the possible errors appear.

Title: Handling Errors In PHP When Using MVC

Body:
Is it good practice to use exceptions and throw/catch exceptions rather than returning 0 or 1 from functions and then using if/else to handle the errors. Thus, making it easier to inform the user about the issue.

No, no, no!

Don't mix exceptions and errors. Exceptions are, well, exceptional. Errors are not. When you ask a user to enter a quantity of a product, and the user enters "hello", it's an error. It's not an exception: there is nothing exceptional in seeing an invalid input from the user. Why can't you use exceptions in non-exceptional cases, like when validating input? Other people explained it already, and shown a valid alternative for input validation.

This also means that the user don't care about your exceptions, and showing the exceptions is both unfriendly and dangerous. For example, an exception during an execution of an SQL query often reveals the query itself. Are you sure you want to take a risk to show such message to everyone?

more than 1 thing could go wrong, such as a database issue, a duplicate entry, a server issue, etc. When an issue happens during registration the user needs to know about it.

Wrong. As a user, I don't need to know your database issues, duplicate entries, etc. I really don't care about your problems. What I do need to know is that I entered a username which already exist. As already said, a wrong input from me must trigger an error, not an exception.

How to output those errors? It depends on the context. For an already used username, I would like to see a small red flag appearing near the username, before even submitting the form, saying that the username is already used. With no JavaScript, the same flag must appear after submission.

For other errors, you would show a full page with an error, or choose another way to inform the user that something went wrong (for example a message which will appear, then fade away at the top of the page). The question is then related more to user experience than to programming.

From programmers point of view, depending of the type of the error, you will propagate it in different ways. For example, in a case of a username already taken, an AJAX request to http://example.com/?ajax=1&user-exists=John will return a JSON object indicating:

That the user already exists,

The error message to show to the user.

The second point is important: you want to be sure that the same message appear both when submitting the form with JavaScript disabled and typing a duplicate username with JavaScript enabled. You don't want to duplicate the text of the error message in server-side source code and in JavaScript!

This is actually the technique used by Stack Exhange websites. For example if I try to upvote my own answer, the AJAX response contains the error to display:

{"Success":false,"Warning":false,"NewScore":0,"Message":"You can't vote for your own post.",
"Refresh":false}

You can also choose another approach, and preset the errors in the HTML page before the form is filled. Pros: you don't have to send the error message in AJAX response. Cons: what about accessibility? Try to browse the page without CSS, and you'll see all the possible errors appear.


答:
I'd partially blame the assembly instruction set.  You've got instructions such as jge for "jump if greater than or equal".  As opposed to "jump if not less than".

Compiler writers may have gone off of what assembly writers came up with, which was presumably based on how it was labeled when being designed on the chip.

...possibly.

Title: Is there any reason why most programming languages don't have '!>' (not greater than) and '!<' (not less than) operators?

Body:
I wonder if there is any reason - or if it is just an accident of history - that there are no !> and !< operators in most programming languages?

a >= b (a greater OR equals b) could be written as !(a < b) (a NOT lesser b), that equals a !< b.

This question struck me when I was in the middle of coding my own expression tree builder. Most programming languages have a != b operator for !(a=b), so why no !> and !< ?

UPDATE:

!< (not lesser) is easier to pronounce than >= (greater or equals)

!< (not lesser) is shorter to type than >= (greater or equals)

!< (not lesser) is easier to understand* than >= (greater or equals)

*because OR is binary operator you brain need to operate two operands (grater, equals), while NOT is unary operator and you brain need to operate only with one operand (lesser).


答:
!< is equal to >=
Now why we have second one not first because all language implement positive operator first and then approach to negative operator,As implementing >= also covers !< and <= covers !>.So language creator goes to these and thought they would be redundant and skip them.

Always try to implement positive case first then go to negative case (:) positive thinking, me personal view only)


问:
RESTful web service and delta updates - advantages and disadvantages
Our front-end developers have requested that the RESTful Java web services to support delta queries. The use case for this is to handle periodic ajax refresh of the screen to bring in new data (deltas). I can see a few advantages of this:

Makes front-end logic simple (i.e. no complicated deduping logic)

Reduce network traffic (i.e. response size is smaller)

However, there are some concern as well:

supporting delta will require the service to be stateful, which
impact scalability

heavy use of caching (results cached per user per query, to determine
the delta)

heavy processing on the server

My questions are:

Are there additional advantages of the delta queries?

What's a good implementation to for delta queries that would
eliminate some of the disadvantages (you can assume we are welling
to drastically refactor our code)

答:
supporting delta will require the service to be stateful, which impact scalability

Not necessarily.  The front-end can provide state information back.  After all, a list of results that's sent in pages is a kind of "delta" query.  A request merely has to include a "maximum" key or timestamp.  Something like ?max=last_seen_key. Everything after this is part of the delta refresh.

heavy use of caching (results cached per user per query, to determine the delta)

Not necessarily.  See above.  The client can send state information back to determine what was already seen.

heavy processing on the server

Completely false.

Are there additional advantages of the delta queries?

No.


问:
Is the Leptonica implementation of 'Modified Median Cut' not using the median at all?
I'm playing around a bit with image processing and decided to read up on how color quantization worked and after a bit of reading I found the Modified Median Cut Quantization algorithm.

I've been reading the code of the C implementation in Leptonica library and came across something I thought was a bit odd.

Now I want to stress that I am far from an expert in this area, not am I a math-head, so I am predicting that this all comes down to me not understanding all of it and not that the implementation of the algorithm is wrong at all.

The algorithm states that the vbox should be split along the lagest axis and that it should be split using the following logic

The largest axis is divided by locating the bin with the median pixel
  (by population), selecting the longer side, and dividing in the center
  of that side. We could have simply put the bin with the median pixel
  in the shorter side, but in the early stages of subdivision, this
  tends to put low density clusters (that are not considered in the
  subdivision) in the same vbox as part of a high density cluster that
  will outvote it in median vbox color, even with future median-based
  subdivisions. The algorithm used here is particularly important in
  early subdivisions, and 3is useful for giving visible but low
  population color clusters their own vbox. This has little effect on
  the subdivision of high density clusters, which ultimately will have
  roughly equal population in their vboxes.

For the sake of the argument, let's assume that we have a vbox that we are in the process of splitting and that the red axis is the largest. In the Leptonica algorithm, on line 01297, the code appears to do the following

Iterate over all the possible green and blue variations of the red color

For each iteration it adds to the total number of pixels (population) it's found along the red axis

For each red color it sum up the population of the current red and the previous ones, thus storing an accumulated value, for each red

note: when I say 'red' I mean each point along the axis that is covered by the iteration, the actual color may not be red but contains a certain amount of red

So for the sake of illustration, assume we have 9 "bins" along the red axis and that they have the following populations

4 8 20 16 1 9 12 8 8

After the iteration of all red bins, the partialsum array will contain the following count for the bins mentioned above

4 12 32 48 49 58 70 78 86

And total would have a value of 86

Once that's done it's time to perform the actual median cut and for the red axis this is performed on line 01346

It iterates over bins and check they accumulated sum. And here's the part that throws me of from the description of the algorithm. It looks for the first bin that has a value that is greater than total/2

Wouldn't total/2 mean that it is looking for a bin that has a value that is greater than the average value and not the median ? The median for the above bins would be 49

The use of 43 or 49 could potentially have a huge impact on how the boxes are split, even though the algorithm then proceeds by moving to the center of the larger side of where the matched value was..

Another thing that puzzles me a bit is that the paper specified that the bin with the median value should be located, but does not mention how to proceed if there are an even number of bins.. the median would be the result of (a+b)/2 and it's not guaranteed that any of the bins contains that population count. So this is what makes me thing that there are some approximations going on that are negligible because of how the split actually takes part at the center of the larger side of the selected bin.

Sorry if it got a bit long winded, but I wanted to be as thoroughas I could because it's been driving me nuts for a couple of days now ;)

答:
In the 9-bin example, 49 is the number of pixels in the first 5 bins.  49 is the median number in the set of 9 partial sums, but we want the median pixel in the set, which is 43 (or 44), and it resides in the 4th bin.

Inspection of the modified median cut algorithm in colorquant2.c of leptonica shows that the actual cut location for the 3d box does not necessarily occur adjacent to the bin containing the median pixel. The reasons for this are explained in the function medianCutApply().  This is one of the "modifications" to Paul Heckbert's original method.  The other significant modification is to make the decision of which 3d box to cut next based on a combination of both population and the product (population * volume), thus permitting splitting of large but sparsely populated regions of color space.

Dan Bloomberg


答:
Is it good practice to use exceptions and throw/catch exceptions
  rather than returning 0 or 1 from functions and then using if/else to
  handle the errors. Thus, making it easier to inform the user about the
  issue.

Yes, yes, yes!

If you want to have clean code, you should almost exclusively use exceptions and don't bother using error codes. Error codes are meaningless. They are almost always tied to some numerical constant that does not reveil much information. It can make your code unreadable and they'll make it hard to propagate data alongside the error.

Exceptions, however, are classes and can contain any information you like. So the user entered a wrong input, like 'abc' for a number field. With an error code you wouldn't be able to propagate this information to the handler of the error without a lot of bubbling. Something that exceptions provide for free. Also, exceptions allow you to have meaningful return values in functions and methods while still having a way to fail elegantly. Even better, Exceptions are propagated right to the place where you want to handle them! Imagine the amount of spaghetti code you'll need to propagate an error code with meaningful data to a handler one or two layers above.

Also, exceptions express so much more semantically than error codes do. Errorcodes lead to spaghetti code where exception handling leads to clean code.

Moreover, it's easy to forget to check status codes. In languages like Java you're forced to handle exceptions (something that for example C# misses).

What's the best way to handle errors in PHP, keeping in mind that I'm
  using an MVC framework.

Use exceptions and handle them in your controllers.

Title: Handling Errors In PHP When Using MVC

Body:
I've been using Codeigniter a lot recently, but one thing that gets on my nerves is handling errors and displaying them to the user. I've never been good at handling errors without it getting messy. My main concern is when returning errors to the user.

Is it good practice to use exceptions and throw/catch exceptions rather than returning 0 or 1 from functions and then using if/else to handle the errors. Thus, making it easier to inform the user about the issue.

I tend to go away from exceptions. My Java tutor at university some years ago told me "exceptions shouldn't be used in production code it's more for debugging". I get the feeling he was lying.

But, an example, I have code that adds a user to a database. During the process more than 1 thing could go wrong, such as a database issue, a duplicate entry, a server issue, etc. When an issue happens during registration the user needs to know about it.

What's the best way to handle errors in PHP, keeping in mind that I'm using an MVC framework.


答:
Consider this handy little class:

```<code>class FunkyFile {

    private $path;
    private $contents = null;

    public function __construct($path) {
        $this->setPath($path);
    }

    private function setPath($path) {
        if( !is_file($path) || !is_readable($path) )
            throw new \InvalidArgumentException("Hm, that's not a valid file!");

        $this->path = realpath($path);
        return $this;
    }

    public function getContents() {
        if( is_null($this->contents) ) {
            $this->contents = @file_get_contents( $this->path );
            if($this->contents === false)
                throw new \Exception("Hm, I can't read the file, for some reason!");
        }

        return $this->contents;
    }

}
</code>```

That's a perfectly fine use of exceptions. From FunkyFile's perspective there's absolutely nothing that can be done to remedy the situtation if either the path is invalid or file_get_contents fails. A truly exceptional situation ;)

But is there any value for your user to know that you've stumbled upon an wrong file path, somewhere in your code? For example:

```<code>class Welcome extends Controller {

    public function index() {

        /**
         * Ah, let's show user this file she asked for
         */
        try {
            $file = new File("HelloWorld.txt");
            $contents = $file->getContents();
            echo $contents;
        } catch(\Exception $e) {
            log($e->getMessage());

            echo "Sorry, I'm having a bad day!";
        }
    }
}
</code>```

Other than telling people you're having a bad day, your options are:

Fallback

Do you have another way of getting the information? In my simple example above, it doesn't seem likely, but consider a master / slave database schema. The master may have failed to respond but maybe, just maybe, the slave is still out there (or vice versa).

Is it the user's fault?

Did the user submit faulty input? Well, tell her about it. You can either bark an error message, or be nice and accompany that error message with a form so she can type in the correct path.

Is it your fault?

And by you, I mean anything that's not the user, so that ranges from you typing a wrong file path, to something going awry in your server. Strictly speaking, it's time for a 503 HTTP error, as, well, the service is unavailable. CI has a show_404() function, you can easily build show_503().

Word of advice, you should take into consideration rogue exceptions. CodeIgniter is a messy piece of code, and you never know when an exception will pop up. Similarly, you may forget about your own exceptions, and the safest option is to implement a catch all exception handler. In PHP you can do that with set_exception_handler:

```<code>function FunkyExceptionHandler($exception) {
    if(ENVIRONMENT == "production") {
        log($e->getMessage());
        show_503();
    } else {
        echo "Uncaught exception: " , $exception->getMessage(), "\n";
    }
}

set_exception_handler("FunkyExceptionHandler");
</code>```

And you can also take care of rogue errors, via set_error_handler. You can either write the same handler as for exceptions, or alternatively convert all errors to ErrorException and let your exception handler deal with them:

```<code>function FunkyErrorHandler($errno, $errstr, $errfile, $errline) {
    // will be caught by FunkyExceptionHandler if not handled
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}

set_error_handler("FunkyErrorHandler");
</code>```

Title: Handling Errors In PHP When Using MVC

Body:
Consider this handy little class:

class FunkyFile {

    private $path;
    private $contents = null;

    public function __construct($path) {
        $this->setPath($path);
    }

    private function setPath($path) {
        if( !is_file($path) || !is_readable($path) )
            throw new \InvalidArgumentException("Hm, that's not a valid file!");

        $this->path = realpath($path);
        return $this;
    }

    public function getContents() {
        if( is_null($this->contents) ) {
            $this->contents = @file_get_contents( $this->path );
            if($this->contents === false)
                throw new \Exception("Hm, I can't read the file, for some reason!");
        }

        return $this->contents;
    }

}

That's a perfectly fine use of exceptions. From FunkyFile's perspective there's absolutely nothing that can be done to remedy the situtation if either the path is invalid or file_get_contents fails. A truly exceptional situation ;)

But is there any value for your user to know that you've stumbled upon an wrong file path, somewhere in your code? For example:

class Welcome extends Controller {

    public function index() {

        /**
         * Ah, let's show user this file she asked for
         */
        try {
            $file = new File("HelloWorld.txt");
            $contents = $file->getContents();
            echo $contents;
        } catch(\Exception $e) {
            log($e->getMessage());

            echo "Sorry, I'm having a bad day!";
        }
    }
}

Other than telling people you're having a bad day, your options are:

Fallback

Do you have another way of getting the information? In my simple example above, it doesn't seem likely, but consider a master / slave database schema. The master may have failed to respond but maybe, just maybe, the slave is still out there (or vice versa).

Is it the user's fault?

Did the user submit faulty input? Well, tell her about it. You can either bark an error message, or be nice and accompany that error message with a form so she can type in the correct path.

Is it your fault?

And by you, I mean anything that's not the user, so that ranges from you typing a wrong file path, to something going awry in your server. Strictly speaking, it's time for a 503 HTTP error, as, well, the service is unavailable. CI has a show_404() function, you can easily build show_503().

Word of advice, you should take into consideration rogue exceptions. CodeIgniter is a messy piece of code, and you never know when an exception will pop up. Similarly, you may forget about your own exceptions, and the safest option is to implement a catch all exception handler. In PHP you can do that with set_exception_handler:

function FunkyExceptionHandler($exception) {
    if(ENVIRONMENT == "production") {
        log($e->getMessage());
        show_503();
    } else {
        echo "Uncaught exception: " , $exception->getMessage(), "\n";
    }
}

set_exception_handler("FunkyExceptionHandler");

And you can also take care of rogue errors, via set_error_handler. You can either write the same handler as for exceptions, or alternatively convert all errors to ErrorException and let your exception handler deal with them:

function FunkyErrorHandler($errno, $errstr, $errfile, $errline) {
    // will be caught by FunkyExceptionHandler if not handled
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}

set_error_handler("FunkyErrorHandler");


问:
Programming a chatterbot - understanding language
I hope this is an answerable question. Let me give it some context:

I am a psychology student and a programmer. I'm going to look into creating a artificial intelligence in the form of a chatterbot. I've been looking around the web, and read about projects such as Eliza which was a first simple psychotherapy program, that has now actually been written in javascript (so you can see how simple this was).

I want to create a chatterbot that can converse, and that will understand semantically and grammatically a sentence, for the purpose of reciprocal communication rather than simply outputting an answer. I'm interested in ways to learn about programming with "language". I know that this is a complex question, so the answer will probably be complex too.

What programming languages/frameworks should I look into when wanting to analyze the semantics. I know of the excellent Wolfram Alpha project that has an API. But I don't want to create an artificial intelligence that can answer any random question.

To paraphrase: What frameworks / programming languages are suited to work with deconstructing linguistic units and understanding language, for the purpose of conversing? Also do you know of any projects that implement these?

答:
Here's a helpful link: http://ai-programming.com/bot_tutorial.htm

That's where I learned a lot of techniques I'm using in my own chatterbot called Quanda Sparks. Although organizing, analyzing, and creating common language algorithmically is a complex subject, and so far no bot has passed the Turing Test (as far as I know), there are a few ways to mimic human speech.

Template Responses: This is a way to make it seem as if a robot understands by having it talk of what the human inputted. Let's say I type in "I like tacos and enchiladas." The bot responds with "What is so great about tacos and enchiladas?" How did it arrive with this response? When it sees "I like", it takes whatever follows and makes a template, in this case "tacos and enchiladas." Then it can construct a sentence with "What is so great about " + template. The robot can fool its audience without ever even know what a taco is.

Generic Responses: Give the bot lots of responses that could fit in almost any scenario. Some examples include "okay", "That's cool", "I hear you", etc. That way, if the bot has nothing to say, it still has a chance at keeping up the act.

Thesaurus: Let's say you have plenty of responses looking for the word "awesome", but the user enters in "amazing". Normally, the bot would be stumped and would have to resort to one of its generic responses; however, if you replace all instances of the word "amazing" with "awesome", it will still be able to find a good response.

Foil cheaters' plans: Users will try all they can to fool the bot into revealing its weaknesses in speech. Some things they will try: leaving the input field blank, entering gibberish, repeating the same thing twice, mimiking the bot, and putting words out of place, such as "you are a bot who". Make sure you give good responses under these circumstances. In the last example, you could check to make sure that there is a word after "who" before telling the bot the user asked a question.

Speak in context: This is the hardest part and the main reason bots fail the Turing Test. Chatterbots can only pretend to understand by giving responses that make sense. If you ask a chatterbot to remember the number 490, talk for a while, and then ask the bot what the number was, most bots will have no clue what you are talking about. Most good bots can look at least one or two lines back. Make sure you also make your bot context-sensitive otherwise.

Do not repeat responses: When you talk to a person, does he usually say "Oh, that's cool ... oh, that's cool ... oh, that's cool" like that three times in a row? No. Even if he is not really interested, he will change up the words like this: "oh, that's cool ... awesome ... that's good." Make sure your bot also waits a while before repeating itself.

Learn from mistakes: It's hard to make the robot learn by itself, but you can teach it more efficiently like this: have people converse with it. Have it record the conversation and any input it does not have a response for. Then, collect this data and you it to build more responses.

I hope these ideas can help you get started. As for what technologies you would need for this, I am programming mine in Java and storing it's knowledge base in a text document. You really don't need anything past that. I was originally going to integrate in an SQL database, but soon found it wasn't worth it. You don't need any fancy APIs. Just use your head and problem-solving ability. If you want to be able to program conversation, you need to understand how conversation works. Study real conversations and look for patterns. When you find one, integrate it.


问:
Standard semantic name for 3rd table in 3NF
For 3 tables that are in 3NF, a many-to-many relationship, is there a standard name or term to describe the 3rd table, the one that associates the other tables? Basically, I'm looking for a semantic way to name the 3rd table.

Example

You have two tables: users and widgets. A user can have multiple widgets and a widget can be owned by multiple users. What is the most semantic name for the 3rd table?

In the past, I've used the following at one time or another:

userWidgets

userWidgetAssn (association)

userWidgetXref (cross-reference)

In my example, userWidgets is probably my top choice, but it doesn't always work as cleanly depending on the table names. Is there an industry standard?

答:
userWidget Singular. (I dropped the s). This is the closest to a standard you will find.

Adding Xref or Assn provides no additional information.

Can you expand on why you went singular rather than plural?

Because when using an ORM I will be referring to userWidget and a Single Object (record) from the userWidget table and userWidgets to refer to a collection of those objects. It's cleaner.


答:
I hope you could bear with me in the next few lines. I don't agree with the naming conventions you have provided. Data Modeling has a purpose of making us think in more detail about the business and not only generate DDLs. If we use the effort and time spent in constructing the model to learn more about the business we could gain a lot. Now you say:

A user can (have) multiple widgets and a widget can be owned by multiple users.

To me, using the word have is not in fully in sync. with the word owned.

If you insist on the part "a widget can be owned by...", you need to say a "a user could own 0,1 or more widgets". This is to make it clear that we are dealing with 1 association (or relationship) in both directions.

Analyzing this further, what does it mean to say "a user owns a widget"? It is not very clear to everyone. Did the ownership occur as a result of a buying process? (as in: user buys a widget) or a granting process? (as in privilege granting)? If the ownership occurred due to a buying process, then the intersection table between the widget and the user is the table capturing the buying history (or buying details) of the user.

Now you can decide if you want to use a descriptive name such as "UserPurchaseDetail" (a better name is suggested below by @Joel Brown) or only use a name like UserWidget.

Again, whatever your choice of the name is, my point is that one should always strive to do more analysis and use a name that reflects what is the table used for in business terms as much as possible.

Edit - Added name suggested by the note below as an alternative name.

Title: Standard semantic name for 3rd table in 3NF

Body:
For 3 tables that are in 3NF, a many-to-many relationship, is there a standard name or term to describe the 3rd table, the one that associates the other tables? Basically, I'm looking for a semantic way to name the 3rd table.

Example

You have two tables: users and widgets. A user can have multiple widgets and a widget can be owned by multiple users. What is the most semantic name for the 3rd table?

In the past, I've used the following at one time or another:

userWidgets

userWidgetAssn (association)

userWidgetXref (cross-reference)

In my example, userWidgets is probably my top choice, but it doesn't always work as cleanly depending on the table names. Is there an industry standard?


问:
How REST is used outside of the web
I was recently reading the Wikipedia article for Resource-Oriented Architectures (ROA) and stumbled across an article that made the assertion that, although REST is a technology that is very-well suited for web applications and web services, that it is nevertheless a standalone technology that can be used in non-web applications.

This is the first I've ever heard of such a thing! I thought REST was a SOAP competitor, but that the two were strictly web service solutions.

My question: can someone provide an example for how REST is used in something that isn't a web app? Like a Swing client, or a command line tool, or an EJB.

答: I used a REST API for a communications server that was used in a radio devices. I'd say SMTP is a REST API too (ie you connect to a resource on port 25 and have verbs like MAILTO, SEND, TO, etc to build up a message)</p>

Title: How REST is used outside of the web


答:
I've seen just using the two.  Just keep the same standard you use for everything else.

If your tables are users and widgets and you use camelCase, then userWidgets is fine.  (I prefer that to usersWidgets because each userWidget is an individual item)  The key is to be consistent every time you do it.  This is more important than which standard.

I've seen it elsewhere with customer and product, and it's essentially the same thing you've described.


答:
From RFC 1925

perfection has been reached not when there is nothing left to add,
  but when there is nothing left to take away.

Adding additional operators that duplicate existing functionality doesn't do anything other than add (unnecessary) complexity to the language (and thus tokenizer and parser).

Consider also in languages where operator overloading is possible, you would have yet another operator to overload.  Consider the confusion when bool operator<= and bool operator!> could return different things (yes, I know one can already make inconsistent comparisons).

Lastly, think of languages where methods or operators are multiply defined (Ruby - I'm looking at you) and you have one programmer who uses <= while another uses !> and you have multiple code styles for the same expression.


答: Here's an irony of most large software firms and technology consultancies:  their internal systems are much worse than you would expect.  If you're a top programmer at Microsoft, you're not developing a new internal ERP, you're working on Bing/Excel/Xbox.  If you're a top ERP expert at Accenture, you're helping clients, not working internal ERP solutions.  So these firms buy external packages, and the implementations are mediocre at best.</p>

Title: Do big software companies develop their business process management solutions (ERP) in-house?

Body:
I was looking at the customer list of a few ERP vendors like SAP. The companies in the list are mostly non IT companies. So, I'm wondering as to how IT companies approach the business process management problem.

For example, any IT company with a few thousand employees across different locations will need software for HR management, accounting, and so on. And a software product vendor (like Microsoft) will need CRM software.

It looks like buying enterprise software from an outside vendor can be a messy and expensive proposition, especially when they can code it in-house using their excellent grasp on the requirements specific to their business.

Do these companies usually build their own solutions using in-house resources or do they buy it from other software vendors?


问:
What's stopping Oracle from supporting identity (auto-numeric) columns?
EDIT: As gavenkoa's answer points out, Oracle Database 12c (released a couple of years after this question was asked) has support for Identity Columns.

As far as I know, Oracle's RDBMS is one of the few (the only?) SQL database products that doesn't support identity/autonumeric columns.

The alternative offered by Oracle is database sequences, a feature in many ways much more powerful than auto-numeric columns, but not equivalent.

It is not that I don't like sequences. What I hate is having a different programming model for generating row identity values between Oracle and any other database. For example, I often try to setup HSQL or SQLite for java apps that will eventually run over an Oracle database when I'm not working specifically on the data layer (just as a stub or mocking database). I cannot do that easily because I need different set of SQL DDL scripts: one for Oracle, and one for everyone else; I also need two sets of Hibernate mapping files if I'm using Hibernate.

What I find intriguing is that Oracle Database, being one of the most complete and robust enterprise software packages of the last decade hasn't put that seemingly basic feature in their product, but almost any other RDBMS, even the smaller ones, has it.

Why?

Why doesn't oracle support a sequence-based identity column shortcut syntax that dumb and lazy people like me can use?

The only reason I can think of is that Oracle does that on purpose as a vendor lock-in strategy so your code is harder to migrate to other RDBMS where your database sequences cannot be used.

Or maybe I'm just wrong and confused? Please enlighten me.

答: I don't know about sequence in Oracle db but I try to avoid using identity columns. Usually identity columns are used as surrogate keys and seem working well at beginning but sooner or later when business requires to transfer/export/import data between systems and clients, identity columns are the one that is most troublesome to deal with.</p>

ContentLicense: CC BY-SA 2.5


问:
How do I make sense of the javascript frameworks explosion ? Should I learn them all?
For a beginner web developer who is still doing web development the conventional way (PHP/J2EE/Struts on server side, HTML/CSS/Javascript on client side), I was bowled over by the recent blog post on Trello technology stack.

I can't help feeling overwhelmed by the list of new technologies and frameworks mentioned in this post and specifically the ubiquitousness of Javascript frameworks.

My question is, is this the future of web development? Are there any articles, websites or resources that can help me make sense of where each of these new frameworks fit in a modern web application ?

答:
I don't think it's physically feasible to expect one to know all (or a quarter of) different JavaScript frameworks out there.  I'm a noob when it comes to web development, but I've dabbled from time to time just to keep things interesting.

My advice would be to just pick a framework that looks interesting and start working with it. jQuery would be my first choice for general purpose utility things. It allows really high-level functionality with few lines of code but if you are a little bit more curious about how it works, it will also teach you just how far you can push JavaScript in terms of language itself (did for me anyway).

Just like learning any other API/library, it will take time but you'll start noticing common themes/patterns and eventually it won't be as overwhelming when starting with a new framework/tool and you'll be able to pick up basic concepts much easier.

So take a step back, then take a deep breath and just look around see where you want to work on and what would you like to build/improve.  If you want to do Trello plug ins, then you know which framework to go look at.


问:
Why should identifiers not begin with a number?
Most programming languages appear to be designed to not allow one to declare an identifier that starts with a number. I was just curious to know the reason. I have already searched the web, but couldn't find a satisfactory explanation.</p>

答: The convenience of the people implementing the lexer.  (No, seriously, that is about it.  Various languages have other reasons, but it ultimately comes down to that.)</p>


答:
Likely this convention has evolved from very early historical language design decisions, as on early machines the entire compiler, including lexical analysis, had to run in a few kWords, less memory than even just the first-level processor data cache on current mobile devices, so the allowed variable names were very limited, and had to be easy to distinguish from numeric constants in very few op codes.

Thus, the convention became what generations of programmers are used to.

Title: Why should identifiers not begin with a number?

Body: Most programming languages appear to be designed to not allow one to declare an identifier that starts with a number. I was just curious to know the reason. I have already searched the web, but couldn't find a satisfactory explanation.</p>


答:
In C/C++, a number followed by a letter is considered to be a numeric constant and the string that follows, qualifies the type of the constant.  So for example (these are VC++, not sure how standard they are):

0 - signed integer

0l - signed long integer

0u - unsigned integer

0i64 - 64 bit signed integer

So a) it is easier for the lexer as Daniel said but also b) it makes an explicit distinction since 0y might be a variable but 0u would never be.  Plus other qualifiers, like "i64" were added way later than "l" or "u" and they want to keep the option open of adding more if needed.


问:
Advantages of Scrum for the developers themselves?
Scrum being a project management methodology, how would you 'sell' it to the developers in a team that is reasonably happy with its current situation?

It seems easy to me to explain to our Product Manager how Scrum will allow him to get regular releases, to amend requirements, and get the team to focus on the high-priority stories first.  I found it easy to explain what TDD or Continuous Integration bring in a developer's day-to-day life.

But how can developers be convinced to embrace Scrum?  How would Scrum make their life easier?

答: People in a Scrum team get to decide many things by themselves: what will be done during the next sprint, how do we break this story in tasks, who works on what, etc.  This empowers them, and is almost the exact contrary to micro-management.</p>


问:
How should I choose the right documentation for my team?
I've asked this question a few days ago about how much documentation should be made and now I realize I may have been asking only half of the question.

My goal is to promote some sort of documentation in order to increase continuous knowledge inside the team.

My team is working mainly on server-side services which extends proprietary devices which are distributed locally (national not global)

In addition we supply APIs and administration web apps to those services.

What would be the best types of documentation for my team?

Should we focus on DFDs, sequence diagrams, class diagrams, just plain text... ?

Are some documentation methodologies better for specific industries or are there some  which are just a waste of time?

I fear this last question would be put down as too subjective, but I do hope there are some standard answers for this question, similarly to when someone asks about good OOP techniques and gets directed to design patterns and SOLID principles.

答:
You should concentrate on what that your team will actually read. There is no point at all to focus on anything, if you haven't got the slightest idea of how your team will respond.

Your best bet is to make documentation part of the process and include everyone in it. There should be some consistency, but let's worry about that when there's actual documentation. What we've done is pretty simple: we added a documentation and a code review sub task to every issue. No issue is resolved, until all sub tasks are resolved, so everyone has to write their own documentation and review others' code.

We use a wiki, so documentation is ever evolving, and at first everyone went about it their own way. For example, I was the only one that used DFDs. After a few months, we started copying each other's style, learning from each other, and we reached a point of quasi-consistent documentation. I went back and revised older posts, and let's say we are at a point where our documentation is good enough.

It would be best not to let anyone get too creative, but other than that, having a quasi-consistent documentation is better than worrying about best practices and industry standards, and never actually getting to write the damn thing.

To summarize, my generic guidelines for documentation are:

Write the damn thing,

Be consistent.

Worry about everything else afterwards.


答:
Consider the following 2 cases:

Case 1

Lets assume that an identifier could begin with a number.

So a statement like below would be valid (since an identifier can have 1 or more characters)  :

int 3;

When I try to use the above variable in a program, it'll result in compiler ambiguity:

int 3,a;

  3=5;

  a=3;

In the statement a=3 what is the role of 3 (is it a variable with value 5 or is it the numeral 3) ?

Case 2

As opposed to the example above, lets assume that a language were to actually allow identifiers starting with a number while still disallowing numerals being used as identifiers. This can cause the following issues:

The language rules regarding the variable which says that a variable can consist of 1 or more characters will have to be redefined to a complex rule like: A variable can have one or more characters and must be unique if it does not start with a number while it cannot be of single character length when starting with a number (etc..)

The compiler will have to check for and report error cases when all numerals (eg 333) and valid alphabet suffixes (e.g. 34L) are being used as variable names. In loosely typed languages like Python and JS where you can use variables on the fly without declaring them, it may even be impossible to check for the special cases involving all numerals e.g. if (33==5) Here, 33 could be an erroneous undeclared variable that the user has declared. But the compiler will not be able to identify this and report the error.

Making this restriction will prevent the programmer from using numbers as identifier names.


答:
Especially with Javascript, I think it is most important to learn the language itself. If you really learn Javascript and understand its wackier corners, then picking up a framework will be cake, and you'll really be able to appreciate all the work the framework is doing for you. More importantly, you'll be able to use native Javascript calls in situations where it's either more efficient or where the framework is doing something you don't want it to.

Also, try and pick frameworks to learn that make the most sense for what you are doing. For example if you are doing vector graphics, learn about Raphael.

And, this is something I myself don't do enough of, don't just learn the frameworks, peek inside them. The great thing about Javascript is that the source code is right in front of your face. Most (all?) frameworks make their source code available in non-compressed form. Look at the source. This will teach you about practical and hopefully good Javascript, and you'll be able to apply this knowledge to whatever framework you use.

Finally, you'll often find necessity dictating the frameworks you learn. If you  know jQuery, but you're brought into a mature project that uses Mootools, you'd better choose to learn Mootools.

Title: How do I make sense of the javascript frameworks explosion ? Should I learn them all?

Body:
For a beginner web developer who is still doing web development the conventional way (PHP/J2EE/Struts on server side, HTML/CSS/Javascript on client side), I was bowled over by the recent blog post on Trello technology stack.

I can't help feeling overwhelmed by the list of new technologies and frameworks mentioned in this post and specifically the ubiquitousness of Javascript frameworks.

My question is, is this the future of web development? Are there any articles, websites or resources that can help me make sense of where each of these new frameworks fit in a modern web application ?


答:
Measure, and use your measurements to guide you. You probably can't (and shouldn't) do split testing on the members of a small group of programmers, but you can change the documentation used at different times, or on different components.

Introduce DFDs: do they help? ...oh, wait, what does it mean to "help"? There are a number of quantities you could measure: team velocity, defect density, team satisfaction, and probably others. So choose the measurements that are important to your team's performance, and find out how different documentation processes/artefacts affect them.

The point here is that documentation is a communication tool, so answering "what documentation should we use?" is tacitly addressing "how does my team communicate?" I don't know that, but you can find out, and you can tailor your documentation strategy to help the people on your team.

Title: How should I choose the right documentation for my team?

Body:
I've asked this question a few days ago about how much documentation should be made and now I realize I may have been asking only half of the question.

My goal is to promote some sort of documentation in order to increase continuous knowledge inside the team.

My team is working mainly on server-side services which extends proprietary devices which are distributed locally (national not global)

In addition we supply APIs and administration web apps to those services.

What would be the best types of documentation for my team?

Should we focus on DFDs, sequence diagrams, class diagrams, just plain text... ?

Are some documentation methodologies better for specific industries or are there some  which are just a waste of time?

I fear this last question would be put down as too subjective, but I do hope there are some standard answers for this question, similarly to when someone asks about good OOP techniques and gets directed to design patterns and SOLID principles.


答:
What would be the best types of documentation for my team?

I am not sure if system documentation have standard types. However, system documentation has goals. These goals stem from the methodology used and the system development phase used. System documentation is also affected by standards such as CMM.

Should we focus on DFDs, sequence diagrams, class diagrams, just plain text... ?

Each type of diagram serves a purpose and is usually tied to a methodology. DFDs are part of Structured Analysis and they are commonly used to describe data flows across systems, programs, and to describe overall system (or subsystem) inputs and outputs.
Class diagrams are part of the UML and the OOA/OOD world. Class diagrams are used to document classes in a system/subsystem and in many cases as the basis for other diagrams and to generate DDLs. Plain text is important for specifying and describing business rules.

Are some documentation methodologies better for specific industries or are there some which are just a waste of time?

Contrary to some people belief's, documentation is NOT a waste of time if done consistently and correctly.

What you must do is study the value of documentation and put in place the specific documents that will be describe your system and that will add value in each of the system development phases, then educate your team in the techniques and value of this work. Most importantly is to plan for all of this in your project schedule.


问:
Is it bad practice to store user input in the same table where the admin stores data?
If in a web app, let's say an app that has a table with stored street address (Strings), the admin of the app will be adding data often to grow his archive.
The table (MySQL) has a primary key with AUTO_INC.

The web app allows the users to add addresses themselves.  Once a user enters an address say X, ALL of the users of the application will be able to see the address X when searching for available addresses.

What if, since address is a string, a user stores inappropriate content(like bad words, for example)? This might offend some users and push them to stop using the app.

So I was thinking of what would be better:

Storing user input in a separate table ("pending input"), until the admin approves them and then they're moved the official table?

Or store the inputs in same table of the admin's inputs table, but put a temporary flag on each entered record (by the users) so that they are only visible to that user until the admin approves them?

On a side note, is it logical to limit each user to have a specific amount of input addresses per day that they can add (some spammers might fill the table with thousands of useless records)?

答:
I would always put data of the same type in one table and rather add some simple columns with flags in a single table. This will make adding new features to your system  in a later stage probably much easier to accomplish. Especially if other developers will be working on the project.

The problem with a limited amount of submissions by users, is that you limit the most active users. You can follow the StackExchange philosophy. The first time a user adds an address, it first needs to be approved. Then you can create a trusted base of users, and there is no reason to restrict those users at all. Don't make it to complicated however. Dividing users in new users and trusted users should be enough, if you also add some opportunity for regular users to report spam-input with a simple button. Do not make your system more restricted than necessary, that will scare of potential active users.


问:
What is the ideal length of a method for you?
In object-oriented programming, there is of course no exact rule on the maximum length of a method , but I still found these two quotes somewhat contradicting each other, so I would like to hear what you think.

In Clean Code: A Handbook of Agile Software Craftsmanship, Robert Martin says:

The first rule of functions is that they should be small. The second
  rule of functions is that they should be smaller than that. Functions
  should not be 100 lines long. Functions should hardly ever be 20 lines
  long.

and he gives an example from Java code he sees from Kent Beck:

Every function in his program was just two, or three, or four lines
  long. Each was transparently obvious. Each told a story. And each led
  you to the next in a compelling order. That’s how short your functions
  should be!

This sounds great, but on the other hand, in Code Complete, Steve McConnell says something very different:

The routine should be allowed to grow organically up to 100-200 lines,
  decades of evidence say that routines of such length no more error
  prone then shorter routines.

And he gives a reference to a study that says routines 65 lines or long are cheaper to develop.

So while there are diverging opinions about the matter, is there a functional best-practice for you?

答:
Functions should normally be short, between 5-15 lines is my personal "rule of thumb" when coding in Java or C#. This is a good size for several reasons:

It fits easily on your screen without scrolling

It's about the conceptual size that you can hold in your head

It's meaningful enough to require a function in its own right (as a standalone, meaningful chunk of logic)

A function smaller than 5 lines is a hint that you are perhaps breaking the code up too much (which makes it harder to read / understand if you need to navigate between functions). Either that or your're forgetting your special cases / error handling!

But I don't think it is helpful to set an absolute rule, as there will always be valid exceptions / reasons to diverge from the rule:

A one-line accessor function that performs a type cast is clearly acceptable in some situations.

There are some very short but useful functions (e.g. swap as mentioned by user unknown) that clearly need less than 5 lines. Not a big deal, a few 3 line functions don't do any harm to your code base.

A 100-line function that is a single large switch statement might be acceptable if it is extremely clear what is being done. This code can be conceptually very simple even if it requires a lot of lines to describe the different cases. Sometimes it is suggested that this should be refactored into separate classes and implemented using inheritance / polymorphism but IMHO this is taking OOP too far - I'd rather only have one big 40-way switch statement than 40 new classes to deal with, in addition to a 40-way switch statement to create them.

A complex function might have a lot of state variables that would get very messy if passed between different functions as parameters. In this case you could reasonably make an argument that the code is simpler and easier to follow if you keep everything in a single large function (although as Mark rightly points out this could also be a candidate for turning into a class to encapsulate both the logic and state).

Sometimes smaller or larger functions have performance advantages (perhaps because of inlining or JIT reasons as Frank mentions). This is highly implementation dependent, but it can make a difference - make sure you benchmark!

So basically, use common sense, stick to small function sizes in most instances but don't be dogmatic about it if you have a genuinely good reason to make an unusually big function.

OwnerDisplayName: iPhoneDeveloper

OwnerDisplayName: mikera

ContentLicense: CC BY-SA 4.0


答:
In OOP all things object and there are these features:

Polymorphism

Abstraction

Inheritance

When you observance these rules then your methods is usually small but don't exist any rule for small or very small (e.g  2-3 line) rules.
A benefit of small method(small unit eg method or function) are:

better readable

maintain better

fixed bug better

changes better

Title: What is the ideal length of a method for you?

Body:
In object-oriented programming, there is of course no exact rule on the maximum length of a method , but I still found these two quotes somewhat contradicting each other, so I would like to hear what you think.

In Clean Code: A Handbook of Agile Software Craftsmanship, Robert Martin says:

The first rule of functions is that they should be small. The second
  rule of functions is that they should be smaller than that. Functions
  should not be 100 lines long. Functions should hardly ever be 20 lines
  long.

and he gives an example from Java code he sees from Kent Beck:

Every function in his program was just two, or three, or four lines
  long. Each was transparently obvious. Each told a story. And each led
  you to the next in a compelling order. That’s how short your functions
  should be!

This sounds great, but on the other hand, in Code Complete, Steve McConnell says something very different:

The routine should be allowed to grow organically up to 100-200 lines,
  decades of evidence say that routines of such length no more error
  prone then shorter routines.

And he gives a reference to a study that says routines 65 lines or long are cheaper to develop.

So while there are diverging opinions about the matter, is there a functional best-practice for you?

OwnerDisplayName: MJM