ソフトウェアの複雑性と「銀の弾丸」

2014年05月18日
小池和彦

ブルックスの法則

遅れたソフトウェア開発に人員を追加投入すると、さらに遅れる

既存メンバーと追加メンバーのコミュニケーションが必要になり、そのコストが増員の効果を上回ってしまうため

銀の弾丸はない

ソフトウェア開発のコストはハードウェアのコストのようには下がらない。ソフトウェア開発の生産性を劇的に改善する方法(狼男を鎮める銀の弾丸)はない。

ソフトウェア開発の本質は「抽象的な概念構造体の構築」。技術革新は起こりにくい

銀の弾丸度

  • インクリメンタル型: ☆☆☆
  • バザール方式: ???

C言語の例


// アドレスの構造体
struct Address {
    char name[128]; // 名前
    char phone[32]; // 電話番号
    struct Address *next; // 次の構造体のポインタ
};

int main(int argc, char *argv[]) 
{
    struct Address *addressList = NULL;

    addressList = addAddress(addressList, "Suzuki Taro", "090-1234-5678");
    addressList = addAddress(addressList, "Tanaka Hanako", "080-7777-8888");

    printAddress(addressList);
}

					    

アドレスの構造体を定義

アドレスのリストを操作する関数に構造体を渡す


// 構造体のリストに名前と電話番号を追加
struct Address *addAddress(
    struct Address *list,
    const char *name,
    const char *phone)
{
	// メモリを確保
    struct Address *newAddr = (struct Address *)malloc(sizeof(struct Address));

	// 確保したメモリに名前と電話番号をコピー
    strncpy(newAddr->name, name, sizeof(newAddr->name));
    strncpy(newAddr->phone, phone, sizeof(newAddr->phone));
    newAddr->next = NULL;

	// 構造体のリストの末尾に作成した構造体を追加    
    if (list == NULL) {
        return newAddr;
    } else {
        struct Address *current = list;
        while (current->next != NULL) {
            current =  current->next;
        }
        current->next = newAddr;
        return list;
    }
}
// 構造体のリストを出力
void printAddress(struct Address *list)
{
    if (list == NULL) {
        return;
    }
	// 一件出力し、再帰呼び出しで次の構造体を処理
    printf("Name: %s; Phone: %s\n", list->name, list->name);
    printAddress(list->next);
}
					    

Address構造体のインスタンス

C++の例


class Address
{
private:
    std::string name;
    std::string phone;
public:
    Address(std::string name, std::string phone) {
        this->name = name;
        this->phone = phone;
    }

    std::string getName() {
        return this->name;
    }
    std::string getPhone() {
        return this->phone;
    }

};
					    

アドレスのクラスを定義


class AddressList
{
private:
    std::list<Address *> addrList;
public:
    void add(std::string name, std::string phone)
    {
        Address *addr = new Address(name, phone);
        this->addrList.push_back(addr);
    }
    void print()
    {
        std::list<Address *>::iterator it;
        for (it = addrList.begin(); it != addrList.end(); ++it) {
            std::cout << "Name: " << (*it)->getName()
                << "; Phone: " << (*it)->getPhone()
                << std::endl;
        }
    }
};
					    

アドレスのリストを操作するクラスを定義

リスト操作そのものはライブラリに任せる


int main(int argc, char *argv[])
{
    AddressList *js = new AddressList();
    js->add("Suzuki Taro", "090-1234-5678");
    js->add("Tanaka Hanako", "080-7777-8888");
        
    js->print();

    return 0;
}
					    

アドレスのデータ構造はAddressListクラスの外部からは見えなくなっている。(情報隠蔽)


class AddressList
{
private:
    std::map<std::string, std::string> addrMap;
public:
    void add(std::string name, std::string phone)
    {
        this->addrMap[name] = phone;
    }
    void print()
    {
        std::map<std::string, std::string>::iterator it;
        for (it = this->addrMap.begin(); it != this->addrMap.end(); ++it) {
            std::cout << "Name: " << it->first
                << "; Phone: " << it->second
                << std::endl;
        }
    }
};
						

アドレスのリストをstd::listではなくstd::mapで管理するよう変更しても、呼び出し側のコードは変更しなくてよい。

JUnitによるJavaプログラムのテスト


public class AddressListTest extends TestCase {
    @Override
    protected void setUp() throws Exception {
        System.setOut(new PrintStream(outContent));
    }
    @Override
    protected void tearDown() throws Exception {
        System.setOut(new PrintStream(outContent));
    }
    private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();

    @Test
    public void testAddAddress() {
        
        AddressList addrList = new AddressList();
        addrList.add("Watanabe Jiro", "03-0001-9999");
        addrList.add("Watanabe Jiro", "03-0002-8888");
        
        addrList.print();
        
        String sep = System.getProperty("line.separator");
        assertEquals("Name: Watanabe Jiro; Phone: 03-0001-9999" + sep
                + "Name: Watanabe Jiro; Phone: 03-0002-8888" + sep,
                this.outContent.toString());
    }

}
					    

銀の弾丸度

  • オブジェクト指向プログラミング: ☆☆☆☆
  • 再利用: ☆☆☆☆☆
  • 自動化: ☆☆
  • 統一モデリング言語: ☆☆☆

デスクトップOSのシェア

Windows 7
  
49.27%
Windows XP
  
26.29%
Windows 8
  
12.24%
OS X
  
7.63%
Other
  
3.66%
Windows Vista
  
2.89%
Linux
  
1.58%
(Desktop OS Market Share as of April 2014 according to Net Applications)

スマートフォンOSのシェア

Android
  
79.0%
iOS
  
14.2%
Windows Phone
  
3.3%
BlackBerry
  
2.7%
Other
  
0.9%
(Mobile OS Market Share as of 2nd quarter 2013 Gartner)

AndroidはLinuxをベースにしている。スマートフォンはパソコンより数が多いことを考えると、現在もっとも使われているのはWindowsではなくLinux

銀の弾丸度

  • フリーソフトウェア運動: ☆☆☆☆☆
  • 知識の共有: ☆☆☆☆☆