问:
What are good ways to organize input files (Makefiles, SConstruct, CMakeLists.txt, etc.) to build automation software?
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>```

答:
GNU autoconf was made to make makefiles maintainable and portable, by moving logic into a separate script.

I would consider using that the first step you could take to manage your Makefiles.


问:
Is TCP/IP an OSI Replacement or both are inter-dependent and meant to work together
I'm confused in differentiating the OSI Model and TCP/IP suite. As per my knowledge. OSI is a structure on top of which Networks are built and TCP/IP is the suite of protocols that operate on these 7 layers of OSI. Correct me if I'm wrong. Also, is TCP/IP a replacement to OSI and is used IN PLACE of OSI? or both these work COLLECTIVELY to form the Network? any good source to clarify my confusion will be appreciated.

Thanks.

答:
The OSI model is a networking model. DECNet has evolved from a 4 layer model to the OSI model.

TCP/IP is a different model and implementation of a network stack.

As they are different models and implementations, there is normally no question of interoperation between the two. If this needs to be done, a network bridge might be used.

In terms of modelling some of the OSI layers can be loosely mapped to the TCP/IP layers, though it is more granular so several OSI layers sometimes map to a single TCP/IP layer.

See this short article comparing the two architectures.

ContentLicense: CC BY-SA 3.0


问:
Passing data between concrete states?
I have a state machine pattern implementation that's pretty straightforward, but I've got a design problem I don't know an elegant solution to.
Here's some partly pseudo code to illustrate.

```<code>class MainRoomState:State

    public override void HandleJoinSuccess(string gameName, List<LobbyPlayer> players)
    {

        Context.CurrentState = new LobbyState(Context);
        //the players list needs to be in the LobbyState
        //that data is specific to the LobbyState
    }
</code>```

Basically, the event triggering the state change also is providing data that belongs in the new state, and I don't know if there's a nice way to do it besides a shared class in the  parent Context object, or by mangling the constructor for this special case.

Edit - in more detail

I have my states setup to encapsulate state specific data as well as logic,  which includes, in this case, a GUI screen belonging to the current state.  This seems to be a more elegant way of handling not only separation of logic, but also state specific data.

Here's what my abstract state looks like,

```<code>public abstract class GameState
{

    public GameState(Game context)
    {
        Context = context;
        Net = context.Net;
    }

    //Incoming events
    public abstract void HandleConnected();
    public abstract void HandleDisconnected(string reason);
    public abstract void HandleNetworkNotification(string msg);
    public abstract void HandleGameStarting();
    //there's about 20 more methods not shown here
</code>```

Here's my Game class,  mainly functioning as a data holder, but it also controls the game loop timer, firing main events, etc.

```<code>public class Game
{
    public Game()
    {
       //...bunch of init code here
       CurrentState = new DisconnectedState(this);
    }
    public GameState CurrentState
    {
        get;
        set;
    }

    //more methods, etc
}
</code>```

You'll see that I opted for composite containment of the CurrentState rather than implementing pass-through methods. That was mostly because I disliked the messiness of passing through the calls when I really didn't need to.  Also, the whole state stores a reference to Context, rather than passing it per method.

I've got two questions/problems with the pattern.

Every concrete state MUST implement in some fashion, EVERY method in the abstract State.  This is ridiculous overkill, and currently most of my states only use 20-40% of the methods, leaving me with a couple pages of this:

public override void HandleGameStarting() { //not handled in this state }

My second issue is that each state has it's own data that only needs to exist while in that state.  I don't want to store a huge conglomeration of data in the Context object when a far more encapsulated way of handling it would be putting it in the state.

Looking over your example,  I suppose one answer to my original question is that I could properly pass through the methods to the Current State,  and just do a kind of hack with the data,

class Game

```<code>public override void HandleJoinSuccess(string gameName, List<LobbyPlayer> players)
{

    CurrentState = new LobbyState(this);
    CurrentState.HandleData(gameName,players);
    //the players list needs to be in the LobbyState
    //that data is specific to the LobbyState
}
</code>```

答:
I think you may be getting a little bogged down in the English meaning of state, when compared to the State Pattern (or Finite-State Machine, which is really a diagrammatic representation of a State Pattern). Both are appropriate here, but they shouldn't be confused.

The State Pattern is something which should, given various common stimuli, operate on the game state differently at different times in the game. So, as you've rightly concluded, the lobby stage (which I'm assuming to be while people are joining a game) is a State in that context.

The game state is a list of players, pieces, cards, dice, whatever else, and all the information required to simulate them. You might want to call that the context.

Each State should receive a UserClicked message from the application which receives the context and coordinates or area clicked and should operate on those accordingly. The information that you are trying to give ownership of to the State object does not belong there, it belongs in the game itself, alongside the State.

The state may also have a UserPressedKey method, a TimerTicked method or any other kind of stimulus on which it should act. But each of these should act on the game state rather than being the game state.

One important method of the State will be ScreenRefresh, which will draw the context for the user.

Here is a very rough example:

```<code>abstract class ApplicationState {

    void Begin(GameContext context);
    void UserClicked(GameContext context, int x, int y);
    void UserPressedKey(GameContext context, char key);
    void TimerTicked(GameContext context);
    void ScreenRefresh(GameContext context);

    protected void OnStateChanged(ApplicationState newState) {

        // inform interested parties that state has changed,
        // using the observer pattern

    }

}

class LobbyState : ApplicationState
{
    void Begin(GameContext context) {

        context.Players = new User[context.NoOfPlayers];

    }

    void UserClicked(GameContext context, int x, int y) {

        // Find a displayed player box which contains click coords

        int index = -1;
        for (i=0; i < context.Players.Length; i++) {
            if (PlayerBox[i].Contains(x, y)) {
                index = i;
            }
        }

        if (index > -1) {

            if (context.Player[index] == null) {
                context.Player[index] = context.ActivePlayer;
            } else if (context.Player[index] == context.ActivePlayer()) {
                context.Player[index] = null;
            } else {
                ErrorSound.Play();
            }

        } else if (CloseIcon.Contains(x, y)) {

            OnStateChanged(new ExittingState());

        } else {

            ErrorSound.Play();

        }

    }

    void UserPressedKey(GameContext context, char key) {

         if (key = 'J' or key = 'j') {

             if (! context.AddPlayerRandomly(context.ActiveUser)) {
                 ErrorSound.Play();
             }

             if (context.GameIsNowFull()) {
                 OnStateChanged(new InitializingState());
             }

         } else if key = Esc {

             if (!context.RemovePlayer(context.ActiveUser)) {
                 ErrorSound.Play();
             }

         } else {

             ErrorSound.Play();

         }

    }

    void TimerTicked(GameContext context) {

        // there is no use for a game timer while
        // we're trying to fill the game, but you
        // want one to tick anyway, because the
        // application doesn't know which state
        // it is in.

    }

    void ScreenRefresh(GameContext context) {

       DrawPlayerBoxes(context.Screen, context.Players);
       DrawExitIcon(context.Screen);

    }

}

class InitializingState : ApplicationState {

    private double waitSpinnerAngle = 0;

    void Begin(GameContext context) {

        context.RandomizePlayOrder();
        context.ShuffleCards();

        // all other game initialization rules here

        OnContextChanged(new PlayerUpState(context.Players[0]));

    }

    void UserClicked(GameContext context, int x, int y) {

        // Not responding to user input for a moment
        ErrorSound.Play();

    }

    void UserPressedKey(GameContext context, char key) {

        // Not responding to user input for a moment
        ErrorSound.Play();

    }

    void TimerTicked(GameContext context) {

        waitSpinnerAngle += 0.05;
        if (waitSpinnerAngle > 1) waitSpinnerAngle = 0;

    }

    void ScreenRefresh(GameContext context) {

         DrawWaitSpinner(waitSpinnerAngle);

    }

}
</code>```

See where I'm going with this? The Application itself is then as simple as setting the initial State, hooking a listener into the OnStateChanged event and calling Begin. When the listener hears that the event is called, unhook your old State, hook in the new one, and call Begin again.

Everything else is triggered by events from the mouse, keyboard or timer, passed directly to the current State without knowledge of which State the game is currently in. If you are running this game across a network then you will also need an event for changes of state received from other players.

Everything in your State and Context is now very unit-testable and separation of concerns are observed. Although, you may want to refactor that LobbyState#UserClicked method a bit, among other things.

Remember, this is just a free example and you get what you paid for it. Don't try to apply it directly to your game. Just use it to understand how the State Pattern should work in the context of a game.

Title: Passing data between concrete states?

Body:
I think you may be getting a little bogged down in the English meaning of state, when compared to the State Pattern (or Finite-State Machine, which is really a diagrammatic representation of a State Pattern). Both are appropriate here, but they shouldn't be confused.

The State Pattern is something which should, given various common stimuli, operate on the game state differently at different times in the game. So, as you've rightly concluded, the lobby stage (which I'm assuming to be while people are joining a game) is a State in that context.

The game state is a list of players, pieces, cards, dice, whatever else, and all the information required to simulate them. You might want to call that the context.

Each State should receive a UserClicked message from the application which receives the context and coordinates or area clicked and should operate on those accordingly. The information that you are trying to give ownership of to the State object does not belong there, it belongs in the game itself, alongside the State.

The state may also have a UserPressedKey method, a TimerTicked method or any other kind of stimulus on which it should act. But each of these should act on the game state rather than being the game state.

One important method of the State will be ScreenRefresh, which will draw the context for the user.

Here is a very rough example:

abstract class ApplicationState {

    void Begin(GameContext context);
    void UserClicked(GameContext context, int x, int y);
    void UserPressedKey(GameContext context, char key);
    void TimerTicked(GameContext context);
    void ScreenRefresh(GameContext context);

    protected void OnStateChanged(ApplicationState newState) {

        // inform interested parties that state has changed,
        // using the observer pattern

    }

}

class LobbyState : ApplicationState
{
    void Begin(GameContext context) {

        context.Players = new User[context.NoOfPlayers];

    }

    void UserClicked(GameContext context, int x, int y) {

        // Find a displayed player box which contains click coords

        int index = -1;
        for (i=0; i < context.Players.Length; i++) {
            if (PlayerBox[i].Contains(x, y)) {
                index = i;
            }
        }

        if (index > -1) {

            if (context.Player[index] == null) {
                context.Player[index] = context.ActivePlayer;
            } else if (context.Player[index] == context.ActivePlayer()) {
                context.Player[index] = null;
            } else {
                ErrorSound.Play();
            }

        } else if (CloseIcon.Contains(x, y)) {

            OnStateChanged(new ExittingState());

        } else {

            ErrorSound.Play();

        }

    }

    void UserPressedKey(GameContext context, char key) {

         if (key = 'J' or key = 'j') {

             if (! context.AddPlayerRandomly(context.ActiveUser)) {
                 ErrorSound.Play();
             }

             if (context.GameIsNowFull()) {
                 OnStateChanged(new InitializingState());
             }

         } else if key = Esc {

             if (!context.RemovePlayer(context.ActiveUser)) {
                 ErrorSound.Play();
             }

         } else {

             ErrorSound.Play();

         }

    }

    void TimerTicked(GameContext context) {

        // there is no use for a game timer while
        // we're trying to fill the game, but you
        // want one to tick anyway, because the
        // application doesn't know which state
        // it is in.

    }

    void ScreenRefresh(GameContext context) {

       DrawPlayerBoxes(context.Screen, context.Players);
       DrawExitIcon(context.Screen);

    }

}

class InitializingState : ApplicationState {

    private double waitSpinnerAngle = 0;

    void Begin(GameContext context) {

        context.RandomizePlayOrder();
        context.ShuffleCards();

        // all other game initialization rules here

        OnContextChanged(new PlayerUpState(context.Players[0]));

    }

    void UserClicked(GameContext context, int x, int y) {

        // Not responding to user input for a moment
        ErrorSound.Play();

    }

    void UserPressedKey(GameContext context, char key) {

        // Not responding to user input for a moment
        ErrorSound.Play();

    }

    void TimerTicked(GameContext context) {

        waitSpinnerAngle += 0.05;
        if (waitSpinnerAngle > 1) waitSpinnerAngle = 0;

    }

    void ScreenRefresh(GameContext context) {

         DrawWaitSpinner(waitSpinnerAngle);

    }

}

See where I'm going with this? The Application itself is then as simple as setting the initial State, hooking a listener into the OnStateChanged event and calling Begin. When the listener hears that the event is called, unhook your old State, hook in the new one, and call Begin again.

Everything else is triggered by events from the mouse, keyboard or timer, passed directly to the current State without knowledge of which State the game is currently in. If you are running this game across a network then you will also need an event for changes of state received from other players.

Everything in your State and Context is now very unit-testable and separation of concerns are observed. Although, you may want to refactor that LobbyState#UserClicked method a bit, among other things.

Remember, this is just a free example and you get what you paid for it. Don't try to apply it directly to your game. Just use it to understand how the State Pattern should work in the context of a game.


问:
Why does the use of interface-based programming appear to be limited to behaviour?
I have been doing a little thinking about inheritance vs. realization vs. composition. I am not about to post the whole detail here. So I was wondering, when we are not talking about creating interfaces to facilitate unit testing: Why does interface-based programming seem to focus upon the grouping of common behaviour, e.g., IPettable (for an animal), IEditable (for a user control), ISubmitable (for a form), etc. Why does the use of interface-based programming appear to be limited to behaviour and not essences. We could pragmatically use an interface, not so much realize behaviour but, to realize commonsense physical similarities which could have nothing to do with behaviour? It is not that there is some limiting feature within interface-based programming that we do not think to do this. This means that there is a tendency to use an interface in a fraction of its possible ways; so how come?</p>

答:
Interfaces effectively define a presentation contract, and provide a means to offer compatibility between classes at a very abstract level. When you use an interface, you are effectively saying "this class is defined in one way, but can be used in another way to be compatible with another class".

Basically you are defining a use case. You aren't usually going to ask an object for it's properties via an interface if you have access to the object itself. You will however be normally asking that object to behave in a manner that might be consistent with the behavior of other class types in a system, so that each can be called and expected to behave in a similar and consistent manner.  That's Polymorphism 101.

Now, I'll contradict myself a little.  I said earlier that you normally don't ask the class for it's properties via an interface. The intention with interfaces as defined is certainly to behave that way. However you can request that a class provide you with it's properties via an Interface, but you use method instead of property syntax.  In this case, you are requesting the class (via an interface) to behave in a manner that allows you to retrieve values via a getter method. It's classic request/response behaviour, which is totally in keeping with the fundamental behavioral nature of Interfaces, while not precluding the ability to treat a class as if it were merely a simpler data structure, or a type compatible with other classes via a common Interface abstraction.

Getter/Setter behavior is also in keeping with providing encapsulation for all of your internal variables.  Languages such as Delphi, and now C# with it's automatic properties tend to blur the lines and make properties seem as if they act like mere variables, yet the reality is that for each property there is a getter and setter method underneath the hood for each property. And if not, there should be in order to preserve encapsulation.

Taken from this perspective, Interfaces aren't limited to only behavior. They effectively are enhanced by it, and in turn enhance the classes which implement them.

OwnerDisplayName: Carnotaurus


答:
The OSI stack is a rather theoretical model (and standard) for networking layers, but it has little practical relevance and mainly survives as a subject of CS classes.

TCP/IP is a suite of concrete networking protocols that have seen overwhelming adoption on the internet. It roughly maps to the layers 3 and 4 in the OSI model.

Concrete protocols rarely fit the OSI model perfectly, e.g. layers 1 and 2 are usually combined, as are layers 6 and 7 (often also 5).

Title: Is TCP/IP an OSI Replacement or both are inter-dependent and meant to work together

Body:
I'm confused in differentiating the OSI Model and TCP/IP suite. As per my knowledge. OSI is a structure on top of which Networks are built and TCP/IP is the suite of protocols that operate on these 7 layers of OSI. Correct me if I'm wrong. Also, is TCP/IP a replacement to OSI and is used IN PLACE of OSI? or both these work COLLECTIVELY to form the Network? any good source to clarify my confusion will be appreciated.

Thanks.


问:
How many developers before continuous integration becomes effective for us?
There is an overhead associated with continuous integration, e.g., set up, re-training, awareness activities, stoppage to fix "bugs" that turn out to be data issues, enforced separation of concerns programming styles, etc.

At what point does continuous integration pay for itself?

EDIT: These were my findings

The set-up was CruiseControl.Net with Nant, reading from VSS or TFS.

Here are a few reasons for failure, which have nothing to do with the setup:

Cost of investigation: The time spent investigating whether a red light is due a genuine logical inconsistency in the code, data quality, or another source such as an infrastructure problem (e.g., a network issue, a timeout reading from source control, third party server is down, etc., etc.)

Political costs over infrastructure: I considered performing an "infrastructure" check for each method in the test run. I had no solution to the timeout except to replace the build server. Red tape got in the way and there was no server replacement.

Cost of fixing unit tests: A red light due to a data quality issue could be an indicator of a badly written unit test. So, data dependent unit tests were re-written to reduce the likelihood of a red light due to bad data. In many cases, necessary data was inserted into the test environment to be able to accurately run its unit tests. It makes sense to say that by making the data more robust then the test becomes more robust if it is dependent on this data. Of course, this worked well!

Cost of coverage, i.e., writing unit tests for already existing code: There was the problem of unit test coverage. There were thousands of methods that had no unit tests. So, a sizeable amount of man days would be needed to create those. As this would be too difficult to provide a business case, it was decided that unit tests would be used for any new public method going forward. Those that did not have a unit test were termed 'potentially infra red'. An intestesting point here is that static methods were a moot point in how it would be possible to uniquely determine how a specific static method had failed.

Cost of bespoke releases: Nant scripts only go so far. They are not that useful for, say, CMS dependent builds for EPiServer, CMS, or any UI oriented database deployment.

These are the types of issues that occured on the build server for hourly test runs and overnight QA builds. I entertain that these to be unnecessary as a build master can perform these tasks manually at the time of release, esp., with a one man band and a small build. So, single step builds have not justified use of CI in my experience. What about the more complex, multistep builds? These can be a pain to build, especially without a Nant script. So, even having created one, these were no more successful. The costs of fixing the red light issues outweighed the benefits. Eventually, developers lost interest and questioned the validity of the red light.

Having given it a fair try, I believe that CI is expensive and there is a lot of working around the edges instead of just getting the job done. It's more cost effective to employ experienced developers who do not make a mess of large projects than introduce and maintain an alarm system.

This is the case even if those developers leave. It doesn't matter if a good developer leaves because processes that he follows would ensure that he writes requirement specs, design specs, sticks to the coding guidelines, and comments his code so that it is readable. All this is reviewed. If this is not happening then his team leader is not doing his job, which should be picked up by his manager and so on.

For CI to work, it is not enough to just write unit tests, attempt to maintain full coverage, and ensure a working infrastructure for sizable systems.

The bottom line: One might question whether fixing as many bugs before release is even desirable from a business prespective. CI involves a lot of work to capture a handful of bugs that the customer could identify in UAT or the company could get paid for fixing as part of a client service agreement when the warranty period expires anyway.

答:
I set up Jenkins this week to build a small .NET project I'm working on. I integrated it with my Git source control so that it triggered a build on every commit. I integrated the unit tests into the build. I integrated static analysis in the form of FxCop and StyleCop violations.

Now every time I check in, it checks out all of my code, builds it, increments the version number across all assemblies, tests it, analyses it for FxCop and StyleCop violations, archives the build and records the results in a number of graphs so I have visibility over time of test results and violations.

Doing that from scratch takes an hour or so (maybe a day with Google if you've not done it before). It costs nothing because all the tools are available for free.

If, as and when the project builds I have a high quality infrastructure that will grow with it at no cost. If or when new developers join the project I can get total visibility on their work and their impact on the project for no cost.

So the only scenario I can see CI not being worth while is either for a project that will take a day or so and then never get revisited, or one in a language where there are no existing / free tools available and the cost of acquiring them is disproportional to the work.


问:
Is a traditional client app which connects directly to a database a good idea?
After using Django's excellent admin interface, I was pondering creating a similar system which wasn't as tied to an ORM.

Now, while considering this, I thought that overcoming webapps limitations (basic widgets, sessions, text/HTTP-based forms, distinct client-side/server-side languages in most cases with a limited communication mechanism, etc.) were a big timewaster, and that maybe traditional GUI development was a better option.

So that brought me to using a desktop app, and then a server part which connects to the database and exposes it via RPC (web services, whatever) to the desktop app, handling security in the traditional webapp fashion.

However, nowadays you can connect to databases remotely securely using SSL, and supposedly databases do provide sufficient role-based authorization (GRANT/REVOKE), so why not connect directly to the database and avoid having to code a server?

Is that a good idea? Are there unassailable problems with this approach? [I think that coupled with good database introspection, one could write a relatively simple framework which would enable very nice RAD of database-based apps)? Which are theoretical problems and which ones are problems with specific implementations?

bonus question: do databases provide enough authorization? While doing my research, I came across the following discussion thread:

http://archives.postgresql.org/message-id/4AE02DF0.40101@enterprisedb.com

which pokes some holes into traditional view-based row access control in the PostgreSQL implementation.

答:
There are different points you need to consider regarding connecting an application directly to a database and relying on userid as a security control mechanism:

How to secure the database connection credentials on the client. There is no easy way I know of that is 100% guaranteed.

It is usually better to design security around the concept of a role and associate the role with a userid. linking userid to authorization is not very flexible. Databases I know only support userid permissions.

To connect to a database directly, you need to:

3.A. Encrypt data communicated between the server and the client

3.B. Bypass firewalls on the client (at least) and have specific server port open. Not all service providers allow this.

Web Services and Microsoft Silverlight using RIA Services allow you to overcome this problem.

I would suggest that you don't connect directly to the database because of the above and the possible security issues if the application data need to be secure.


答: If your primary concern is usability, a desktop application absolutely is the way to go. Most modern languages that have GUI toolkits also have robust libraries for communicating with databases.</p>

Title: Is a traditional client app which connects directly to a database a good idea?

Body:
After using Django's excellent admin interface, I was pondering creating a similar system which wasn't as tied to an ORM.

Now, while considering this, I thought that overcoming webapps limitations (basic widgets, sessions, text/HTTP-based forms, distinct client-side/server-side languages in most cases with a limited communication mechanism, etc.) were a big timewaster, and that maybe traditional GUI development was a better option.

So that brought me to using a desktop app, and then a server part which connects to the database and exposes it via RPC (web services, whatever) to the desktop app, handling security in the traditional webapp fashion.

However, nowadays you can connect to databases remotely securely using SSL, and supposedly databases do provide sufficient role-based authorization (GRANT/REVOKE), so why not connect directly to the database and avoid having to code a server?

Is that a good idea? Are there unassailable problems with this approach? [I think that coupled with good database introspection, one could write a relatively simple framework which would enable very nice RAD of database-based apps)? Which are theoretical problems and which ones are problems with specific implementations?

bonus question: do databases provide enough authorization? While doing my research, I came across the following discussion thread:

http://archives.postgresql.org/message-id/4AE02DF0.40101@enterprisedb.com

which pokes some holes into traditional view-based row access control in the PostgreSQL implementation.


问:
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).

答: I think the answer is simply that there's no need for a !< operator. As you pointed out in your question there is already >= and <= along with the possibility to negate an existing expression, so why add another operator?


答:
Transact-SQL has !> (not greater than) and !< (not less than) operators.

So, other than you, someone at Sybase Microsoft also thought it would be a good idea. Just like Microsoft Bob! :)

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).


答:
Because it doesn't make much sense to have two different operators with exactly the same meaning.

“not greater” (!>) is exactly the same as “lesser or equal” (<=)

“not lesser” (!<) is exactly the same as “greater or equal” (>=)

This does not apply to “not equals” (!=), there is no operator with the same meaning.

So, your modification would make the language more complicated with no no benefit.


答:
I think I saw some languages a few years ago where, instead of the != operator (not equals), something like <> was used. Can't remember their names, though...

I think that it's harder to read !(a < b) or a !< b than a >= b . Probably that's the reason why !< is not used (it does look ugly in my opinion).


问:
What does the term "fast follower" mean?
In the last few days, I've heard the term "fast follower" mentioned several times. It's used in the context of an unresolved bug/issue that (supposedly) will be quickly fixed and implemented.

Is this some new corporate jargon? I'm aware of a fast follower strategy, or second mover strategy (as described in this wikipedia article), but that doesn't apply in the context.

答:
"Fast follower" is a code word for we have already failed because we don't take any calculated risks on implementing our own innovative ideas. It means we won't do anything until someone else has succeeded in doing it and by then it is too late in the game.

I worked for a billion dollar a year company that used to espouse this as a virtue. Guess what they laid off half the company ( 900+ ) people in a single day and the stock has been in the tank for years because of this idiotic mind set.

In your case someone is using a term they don't understand in the incorrect context.


问:
Creating an expandable, cross-platform compatible program "core"
Basically the brief is relatively simple. We need to create a program core. An engine that will power all sorts of programs with a large number of distinct potential applications and deployments.

The core will be an analytics and algorithmic processor which will essentially take user-specific input and output scenarios based on the information it gets, whilst recording this information for reporting.

It needs to be cross platform compatible. Something that can have platform specific layers put on top which can interface with the core.

It also needs to be able to be expandable, for instance, modular with developers being able to write "add-ons" or "extensions" which can alter the function of the end program and can use the core to its full extent.

(For instance, a good example of what I'm looking to create is a browser. It has its main core, the web-kit engine, for instance, and then on top of this is has a platform-specific GUI and can also have add-ons and extensions which can change the behavior of the program.)

Our problem is that the extensions need to interface directly with the main core and expand/alter that functionality rather than the platform specific "layer".

So, given that I have no experience in this whatsoever (I have a PHP background and recently objective-c), where should I start, and is there any knowledge/wisdom you can impart on me please?

Thanks for all the help and advice you can give me. :) If you need any more explanation just ask. At the moment its in the very early stages of development, so we're just researching all possible routes of development.

Thanks a lot

答:
I've seen a team fall into this trap (well, they actively ran towards it and jumped into it, and subsequently died on the spikes).

The problem is that there is a whole lot of reinventing the wheel.  Think of how much time it is going to take to develop all those plugins/user-extensible stuff that is the actual core of what you're trying to do.  Now, you have this extra huge task of building a framework/core.  Your actual business need (the first stuff) will be delayed by 6mos-12mos by developing the core.  Plus, your core will be fresh code and you will expend considerable effort fixing bugs that don't relate to your actual business need.

The path to success is to find something that is mature (not just one guy's open source project which hasn't been updated in 3 years) and already exists and does 90%+ of what you want.  Then make it do the other 10% or adjust your design to fit the constraints.  For your case if you want an end user app Java is a no-brainer, or something that runs out of a browser if you want remote access.  That way you're getting the millions of hours of testing and product maturity for free.  And you can deliver 12 months earlier.

The danger is when people say (and sell to their bosses) that "there's nothing out there that does exactly what we want."  Of course not, but that doesn't mean you reinvent the wheel, you adapt.  "I don't like (one nitpick about linux) so we need to write an operating system!"  It sounds silly doesn't it?  Yet teams do this all the time.  Not saying that this is the case for your group, just know that there are lots of dead projects on the spikes in that pit ahead.

ContentLicense: CC BY-SA 2.5


问:
Does your company have a coding standard?
I recently saw that Microsoft released a coding standards document (All-In-One Code Framework Coding Standards) and it got me thinking...  The company that I work for has no formal coding standards at all.  There are only a few developers and we have been together long enough to have evolved into similar styles and its never been an issue.

Does the company you work for have a documented coding standards?  If no, why not?  Does having a standard make a difference?  Is it worth writing a standard from scratch or should you adopt another standard as your own (ie. make Microsoft's standards yours)?

答:
It's important for a team to have a single coding standard for each language to avoid several problems:

A lack of standards can make your code unreadable.

Disagreement over standards can cause check-in wars between developers.

Seeing different standards in the same class can be extremely irritating.

I'm a big fan of what Uncle Bob has to say about standards:

Let them evolve during the first few iterations.

Let them be team specific instead of company specific.

Don't write them down if you can avoid it. Rather, let the code be
  the way the standards are captured.

Don't legislate good design. (e.g. don't tell people not to use goto)

Make sure everyone knows that the standard is about communication, and
  nothing else.

After the first few iterations, get the team together to decide.


问:
At what point should I have my Windows developers upgrade to the latest release of Windows?
At what point should I begin upgrading our developer's machines to a later Windows release?

From experience, Microsoft typically has an epic fail about every other O.S. (I am really not trying to start a debate about this, it is my perception let it be) i.e. 2000 was a stable and useful O.S, yet m.e. didn't do well, xp was a great O.S. that many businesses still use, Vista didn't do well (I know that the reason this one didn't do well wasn't really Microsoft's fault and that Vista and 7 are the same major revision), while 7 seems to be an excellent O.S. that will be around for a while--sort of like xp is now.

Anyways, this makes me reluctant to upgrade our development machines to Windows 8.

a. I don't want to cost our business a ton of money for an O.S. that
will only be used for a year or two.

b. They also have to have linux dual boots, and I have read that Windows 8 and grub will not play well together.

I do want our developers to develop in the latest environment and to have a leading edge in any technology they are developing with. I do want to stay ahead of--or at least with--the technology curve, yet I want it to make business sense.

So in particular, should I upgrade their machines at this point?
In general, what calculus should I use for deciding this sort of thing?

edit

They do write desktop UI applications as well as ASP.NET applications. Also, I do make sure that they always have the latest release of Visual Studio.

答:
This is an easy one:

When your customers do.

And there is an important corollary which the bosses on a team I worked on forgot once:

"When do we stop supporting the older version of Windows?"

When your customers do.

It's not sexy, but remember that most of what big companies like MS or driver makers do is backwards compatibility work.  Check out "The New Old Thing" if you haven't.


答:
!< is synonymous with >=. Later is just a way of typing well defined mathematical symbol ≥. You are right that "not less than" is used in spoken language, however it's colloquial and can be ambiguous (can be interpreted ≥ or misinterpreted as >). On the other hand programming and math use clearly defined, unambiguous terminology.

Even in 3-value logic, such as ANSI SQL, not x < y is equivalent of x >= y, as they both give NULL if either x or y is NULL. However, there are non-ANSI compliant SQL dialects, where it's not equivalent, and they do have !<.


问:
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?

答:
If you can avoid shared ownership then your application will be simpler and easier to understand and hence less susceptible to bugs introduced during maintenance. Complex or unclear ownership models tend to lead to difficult to follow couplings of different parts of the application through shared state that may not be easily trackable.

Given this, it is preferable to use objects with automatic storage duration and to have "value" sub-objects. Failing this, unique_ptr may be a good alternative with shared_ptr being - if not a last resort - some way down the list of desirable tools.

OwnerDisplayName: ronag

Title: std::shared_ptr as a last resort?

OwnerDisplayName: Charles Bailey


答:
I don't believe I've ever used std::shared_ptr.

Most of the time, an object is associated with some collection, to which it belongs for its entire lifetime.  In which case you can just use whatever_collection<o_type> or whatever_collection<std::unique_ptr<o_type>>, that collection being a member of an object or an automatic variable.  Of course, if you didn't need a dynamic number of objects, you could just use an automatic array of fixed-size.

Neither iteration through the collection or any other operation on the object requires a helper function to share ownership... it uses the object, then returns, and the caller guarantees that the object stays alive for the entire call.  This is by far the most used contract between caller and callee.

Nicol Bolas commented that "If some object holds onto a naked pointer and that object dies... oops." and "Objects need to ensure that the object lives through that object's life. Only shared_ptr can do that."

I don't buy that argument.  At least not that shared_ptr solves this problem.  What about:

If some hash table holds onto an object and that object's hashcode changes... oops.

If some function is iterating a vector and an element is inserted into that vector... oops.

Like garbage collection, default use of shared_ptr encourages the programmer not to think about the contract between objects, or between function and caller.  Thinking about correct preconditions and postconditions is needed, and object lifetime is just a tiny piece of that bigger pie.

Objects don't "die", some piece of code destroys them.  And throwing shared_ptr at the problem instead of figuring out the call contract is a false safety.

Title: std::shared_ptr as a last resort?

Body:
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?

OwnerDisplayName: Ben Voigt


答:
The reason is that operators in programming languages borrow from the mathematical tradition and in mathematics noone realy uses "not greater" and "not smaller" since "smaller or equal" and "greater or equal" do just as good of a job.

So in Programming languages we usually get a symbol looking like ≠ for not equals (!= or /=, unless someone if being fancy with <> or a textual operator)

and things that look like ≤ and  ≥ (<= and >=)

Btw, I don't agree with your assertion that NOT is simpler to understand and reason about then OR. In mathematics, proofs involving lots of negations (like reduction to absurd) are usually frowned upon if there is a more direct alternative available. Also, in the ordering case, the basic knowledge we have (and that is used when thinking or proving something) is the tricotomy between <, = and > so any !< statement probably has to be converted to >= if you want to do anything useful with it.


答:
The world that Bjarne lives in is very... academic, for want of a better term. If your code can be designed and structured such that objects have very deliberate relational hierarchies, such that ownership relationships are rigid and unyielding, code flows in one direction (from high-level to low-level), and objects only talk to those lower in the hierarchy, then you won't find much need for shared_ptr. It's something you use on those rare occasions where someone has to break the rules. But otherwise, you can just stick everything in vectors or other data structures that uses value semantics, and unique_ptrs for things you have to allocate singly.

While that's a great world to live in, it's not what you get to do all of the time. If you cannot organize your code in that way, because the design of the system you're trying to make means that it is impossible (or just deeply unpleasant), then you're going to find yourself needing shared ownership of objects more and more.

In such a system, holding naked pointers is... not dangerous exactly, but it does raise questions. The great thing about shared_ptr is that it provides reasonable syntactic guarantees about the lifetime of the object. Can it be broken? Of course. But people can also const_cast things; basic care and feeding of shared_ptr should provide reasonable quality of life for allocated objects who's ownership must be shared.

Then, there are weak_ptrs, which cannot be used in the absence of a shared_ptr. If your system is rigidly structured, then you can store a naked pointer to some object, safe in the knowledge that the structure of the application ensures that the object pointed to will outlive you. You can call a function that returns a pointer to some internal or external value (find object named X, for example). In properly structured code, that function would only be available to you if the object's lifetime were guaranteed to exceed your own; thus, storing that naked pointer in your object is fine.

Since that rigidity is not always possible to achieve in real systems, you need some way to reasonably ensure the lifetime. Sometimes, you don't need full ownership; sometimes, you just need to be able to know when the pointer is bad or good. That's where weak_ptr comes in. There have been cases where I could have used a unique_ptr or boost::scoped_ptr, but I had to use a shared_ptr because I specifically needed to give someone a "volatile" pointer. A pointer who's lifetime was indeterminate, and they could query when that pointer was destroyed.

A safe way to survive when the state of the world is indeterminate.

Could that have been done by some function call to get the pointer, instead of via weak_ptr? Yes, but that could more easily be broken. A function who returns a naked pointer has no way of syntactically suggesting that the user not do something like store that pointer long-term. Returning a shared_ptr also makes it way too easy for someone to simply store it and potentially prolong the life-span of an object. Returning a weak_ptr however strongly suggests that storing the shared_ptr you get from lock is a... dubious idea. It won't stop you from doing it, but nothing in C++ stops you from breaking code. weak_ptr provides some minimal resistance from doing the natural thing.

Now, that's not to say that shared_ptr can't be overused; it certainly can. Especially pre-unique_ptr, there were many cases where I just used a boost::shared_ptr because I needed to pass a RAII pointer around or put it into a list. Without move semantics and unique_ptr, boost::shared_ptr was the only real solution.

And you can use it in places where it is quite unnecessary. As stated above, proper code structure can eliminate the need for some uses of shared_ptr. But if your system cannot be structured as such and still do what it needs to, shared_ptr will be of significant use.

Title: std::shared_ptr as a last resort?


答:
I don't remember if last "resort" was the exact word he used, but I believe that the actual meaning of what he said was last "choice": given clear ownership conditions; unique_ptr, weak_ptr, shared_ptr and even naked pointers have their place.

One thing they all agreed upon is that we're (developers, book authors, etc)  all in the "learning phase" of C++11 and patterns and styles are being defined.

As an example, Herb explained we should expect new editions of some of the seminal C++ books, such as Effective C++ (Meyers) and C++ Coding Standards (Sutter & Alexandrescu), a couple of years out while the industry's experience and best practices with C++11 pans out.

Title: std::shared_ptr as a last resort?


问:
Help understanding server-side scripting
As far as I understand, there are basically 3 options for doing server-side scripting these days:

Using scripting languages that can be directly interpreted/executed by the web server (e.g., PHP and ASP), where the scripts are interpreted/executed on the fly (i.e., as HTTP requests come), the output is embed into HTML pages is then sent back to the client.

Using any language (e.g., C, C++, PERL, Python) the operating system of the server is capable of executing (either using an interpreter or using the executable file already compiled) and then using CGI to communicate between the web server and the OS. Output of the scripts comes via CGI to the server in the form of complete HTML pages, and is then sent back to the client.

Using Java on a server that can handle servlets/JSPs, which is pretty much the same idea as option 1 above, except using Java instead of PHP/ASP.

Questions:

Is my understanding so far on track, or did I get something wrong?

Are ASP and PHP the only languages that can be interpreted and executed directly by a web server?

Where does Ruby fall in the classification above? Can it be interpreted/executed by servers like PHP? Or does it communicate via CGI?

Is server-side scripting via CGI becoming obsolete or not at all?

答:
Your understanding is correct, if you're from the past. You're pretty much describe as it looked like in 1990s.

Yes, many languages can be executed directly by a web server plugin. Right on for PHP, mod_php for Apache is still the most popular way to host it. However, high-traffic sites use more modern approach, using web server only as a proxy for FastCGI (in case of PHP it's PHP-FPM)

the output is embed into HTML pages is then sent back to the client.

I think you're referring to early 90's so called spaghetti code, however modern approach is to use one of many MVC frameworks. In case of PHP that would mean for example Zend Framework (there are numerous alternatives).

As for ASP, you're probably referring to so called "classic ASP", which is obsolete. Currently it's ASP.NET, which can use any of .NET languages (C# being the most popular), and of course the .NET framework.

C and C++ are not typically used for web application. If so, such services are implemented either as stand alone servers, as module for web server or as FastCGI.

Perl can be executed directly from web serve module using mod_perl. There is also PSGI, which is basically clone of Python's WSGI.

Python is very popular language for web apps. It can be directly executed from Apache web server via mod_python, however that is obsolete and not recommended. Currently the way to go with Python is either via WSGI server module. WSGI server implemented in Python (eg. CherryPy, WebPy) or using stand alone Python web stack (Tornado and Twisted's Web module are fine examples). And of course again, you'd most probably will be using WSGI compatible MVC framework, Django is the most popular one (again, multiple alternatives available).

Ruby, again very popular language for web apps. Best known for web framework Ruby on Rails, which again is MVC. You can execute Ruby directly from server module via mod_ruby or via FastCGI.

Servlets/JSP are executed in stand-alone J2EE application servers, such as JBoss or Tomcat. It's more commonly used to add web interface to business system rather than to create stand alone web apps.

Classical CGI (ie. spawning process on each request) has become obsolete many years ago. It has been replaced by FastCGI (where process is long-running, rather than spawned on each request), server modules, interfaces such as WSGI and clones and stand-alone solutions.

Also the paradigm of the request processing has evolved, with CGI it was process per request. Then was process pool (or thread pool), each process (thread) handling one request at a time. However now, most modern approach is for web servers and stand-alone frameworks to use event-driven programming.


问:
Is developing games the best way to learn programming?
I heard recently an instructor mentinon that developing games was the best way to learn programming. Besides the fact that everything had to be created in code, he said you really get to fully experience and implement OOP into your programs. In other words everything you make in a game is a literal object both technically and in concept. Is it safe to make this assumption? Or are there always exceptions when learning programming?

note it was geared towards .net / xna / c# development.

答:
I would agree except...

It's just as likely the first programming experience many ever had was building and programming a Lego robot (Mindstorms).

While the general term "game" can define a category so huge as to encompass almost all of programming, when used in the context of the original poster it always seems to mean "writing Doom style games".

As has been stated here before - the best way to learn programming is to have something you really want that requires a program. That is - learn programming by writing the program you want.

One of my first Windows programs was a MIDI controller program, because I really wanted a MIDI controller program, and Windows seemed the perfect fit (sliders, buttons, SDK support for MIDI, etc.). I learned a ton about Windows programming (this was back in the Win 3.1 days) from that program.

I've never been partial to game programming for the reasons mentioned here as well - I don't draw all that well, so any game I make will have poorer graphics that those of an artist. I want to learn to program, not to manage a "game building team" (laudable but totally different exercise).

In the end I quite disagree with the teacher's statement. The best way to learn programming is to write the program you really want.

-R


答:
Let me preface this by saying this is extremely generic and simplified view of what happens.

Web server software (like Apache or IIS) does not interpret any code; it doesn't know how to. All it knows how to do is take a request, look it up in some location on the filesystem, and then send the item requested back to the browser. That's all it does - at a very simple level. This is why when you install Apache and add some php file to the DocumentRoot, you don't get the executed PHP result; just the file back.

The first step in getting the server to do something other than serve files is to add code that tells it to do something else when a specific file is requested; otherwise all it will do is try to serve the file according to its default mime type (which is usually text/plain). This is why when you have an incorrectly configured server, and you request index.php, you see the source code for the file instead of the intended result.

So to get a web server to "understand" PHP, you have to tell it what to do when a request for a file with the .php extension comes in. This is where mod_php comes in. This module offloads the request to a PHP interpreter (how it does that can be configured), which then reads the file, executes the code, compiles the results; and sends the results back to the server, which in turn delivers the results to the client. You then configure the webserver so that all files that have .php in the end should be handled by mod_php.

This basic workflow is applied with other languages as well; the only difference is what the server 'offloads' the request to.

The case for PHP is explained above, there is similarly mod_python, and fastcgi, wsgi and other established protocols on offloading requests that a web server is not designed to handle.

Most common implementations have a long running process that waits for a request on a specific port (or socket). The web server is then configured as a proxy, so that it passes any requests that match a specific pattern to this long-running process and then read the results back.

This is how ruby on rails (rack), python scripts (with wsgi) work.

This is also why simple proxy-like web servers like nginx are very popular. They only do the very basic tasks of a traditional web server - serve the "static" files, and are very good at offloading requests to other proxy servers to handle things like PHP, Python, ASP, et. al.

So in the end you have the web server - which takes care of the static files, anything that doesn't need processing.

You have another process, which knows how to deal with your code (for example, a process that runs the PHP interpreter, or a uWSGI server). This sits and waits for requests from the web server.

Finally, you have systems like upstart and supervisor that manage these processes for you.

Hope this clarifies the matter.

Title: Help understanding server-side scripting

Body:
As far as I understand, there are basically 3 options for doing server-side scripting these days:

Using scripting languages that can be directly interpreted/executed by the web server (e.g., PHP and ASP), where the scripts are interpreted/executed on the fly (i.e., as HTTP requests come), the output is embed into HTML pages is then sent back to the client.

Using any language (e.g., C, C++, PERL, Python) the operating system of the server is capable of executing (either using an interpreter or using the executable file already compiled) and then using CGI to communicate between the web server and the OS. Output of the scripts comes via CGI to the server in the form of complete HTML pages, and is then sent back to the client.

Using Java on a server that can handle servlets/JSPs, which is pretty much the same idea as option 1 above, except using Java instead of PHP/ASP.

Questions:

Is my understanding so far on track, or did I get something wrong?

Are ASP and PHP the only languages that can be interpreted and executed directly by a web server?

Where does Ruby fall in the classification above? Can it be interpreted/executed by servers like PHP? Or does it communicate via CGI?

Is server-side scripting via CGI becoming obsolete or not at all?


问:
What are the effects of including build tools in a code repository when those tools have different licenses than your code?
What effect does including another open-source utility in your source repository have upon your code if they use different licenses?

I tend to use more permissive licenses such as the Apache and MIT.

To allow others to use a project with as little setup as possible I want to include utilities used by the build scripts in the repository (documentation generator, JavaScript minifier, etc).

I understand that things generated by these utilities (documentation, minified JS files) are not derivative works.

What is not as clear to me is the question of whether including some utilities which have more restrictive licenses will create conflicts with my code?

Does the "viral" nature of the GPL threaten to "infect" my code by including GPL utilities in my repository and referencing them from my build scripts?

None of the code will be intermingled, appropriate licenses will remain with each item. I should mostly just be using binaries from the outside sources (.jar, etc). I just want to make sure that "distributing" them in my repository when I upload it to GitHub won't taint everything else.

答:
If you include a GPL tool with your project, then you're distributing that tool, which means that you're supposed to provide the source. If it's something that's commonly available, then I doubt that anybody will care - but if you want to make absolutely sure that everything is kosher, you might want to make the sources available (separately from your main project, since most people won't need them).

If you've made any modifications to the GPL tool, then you must make the source available - but I think you knew that already.

As far as "tainting", that won't be a problem. The fact that two pieces of software are distributed together is irrelevant - what matters is how they fit together. For example, the Apple developer kit contains GCC, GNU make, and a bunch of other GPL tools, along with closed-source tools. And that's perfectly legal.


答: The one thing mentioned by Herb Sutter in a later session is that every time you copy a shared_ptr<> there's an interlocked increment / decrement that has to happen.  On multi-threaded code on a multi-core system, the memory synchronization is not insignificant.  Given the choice it's better to use either a stack value, or a unique_ptr<> and pass around references or raw pointers.

Title: std::shared_ptr as a last resort?


问:
Make a big deal out of == true?
There is a colleague of mine who constantly writes:

```<code>if (someBool == true)
</code>```

It drives me up the wall!  Should I make a big deal of it or just drop it?

答: Coleague of mine called if a loop.  I lived to tell about it.

Title: Make a big deal out of == true?