从技术到管理的对话-Tony与Alex的对话系列

5月末我参加了一次“从技术到管理的”培训,总体来说还是有所收获的。这段时间我一直想把自己的收获总结出来与大家分享,但是也一直没找到一个很好的形式来表达,我想简单的罗列一些规则和技巧是最最乏味的。在我的“关于Tony与Alex的对话系列的一点说明”一文中曾经将“Tony与Alex对话系列”定位为技术类的系列文章,但是经过这几天的思考,发现它同样可以用做管理知识起码是技术管理知识的介绍,这篇Blog将作为本系列中的第一篇围绕管理知识的文章。由于本人现在并非管理角色,所以文章内容的正确性和合理性并不能完全保证。

剧情介绍:这篇文章中Tony的角色是一个部门leader,现在他想将Alex提拔为一个Project Leader,身处管理角色多年的Tony深知从技术角色走向管理角色决不是一蹴而就的事情,思维的转变需要的实践和耐心。下面是Tony和Alex的一次对话。Tony主要想了解一下Alex的在管理方面的涉猎以及存在的不足,顺便给Alex一些原则性的指导。

Tony : Alex, 你入司已经有3年了,而且一直是部门内部的技术骨干,你做的很好。
Alex : (心中很是欢喜,能获得Tony的好评真是一件值得高兴的事情,但Alex仍有些丈二和尚摸不到头)自己只是尽力而为罢了。
Tony : (Tony的慧眼当然很快的看出Alex的心理变化)Alex,你知道公司是如何选拔技术项目经理的么?
Alex : 我只知道我看到的项目经理曾经都是部门内部的技术拔尖的人。
Tony : 说的没错,在我们的公司中一直是“技优则管”,虽然这不是我们追求的理想办法,但是这些都决定于整个国内软件行业的“行情”以及软件行业从业者的思维特点。问你这样一个问题:“如果让你选择你所在项目的主管,你是选一个有技术背景的呢还是选一个毫不技术背景的呢”?
Alex : 我想我会选择前者,和一个有技术背景的主管可能沟通起来更加方便和容易。
Tony : 这也是现在大多数人的想法,即所谓的喜欢“内行管内行”,很多调查公司的调查均证明了这一点。现在国内的软件业发展很快,我们几乎不可能招聘一个有经验的职业的管理者并对之进行行业知识培训,这样的成本和风险都太高,我们唯一的方法就是从我们已有的优秀员工中选拔,对他们进行相关的管理知识培训,使之尽快的进入管理角色。
Alex : 原来如此,我以前还真的没想过这么多。
Tony : 想过进入管理者的行列么?你对管理了解多少呢?
Alex : (微笑)参加过很多次管理相关的培训,但是没有实践过,所以在理解和操作上还差很多。
Tony : 其实这次和你的谈话就是想了解些你自己的想法,顺便将我个人的一些经验和你做一些交流。
Alex : 我会珍惜这次机会的。
Tony : 我本人就是一个从技术角色转到管理角色的一个例子,所以我自己多多少少了解和经历了一些在转型过程中的问题,就这么多年来我的所见所闻而言,我觉得从技术角色到管理角色的转变关键是思维方式的转变。我们可以从一些现象中挖掘到这点。还是要问你一个问题。Alex,你觉得技术人员的特质有哪些呢?
Alex : 你问的是“什么是技术人员的特质”么?我不是十分能理解“特质”的含义,我就拿我自己以及我所看到的技术人员的行为共性说一下吧。我觉得大多数技术人员做事不够灵活,在某件具体的事情上容易钻牛角尖;他们很细心,做事思路清晰,关注细节,一步一步的向前走,也可以说有些按部就班(微笑);喜欢就事论事,一般不针对某个人;认为对就是对,错就是错。
Tony : 说的很好,看来你的观察力和总结能力都非常的不错。外国的很多调查公司都做过这方面的调查,你知道调查出的结果是什么么?
Alex : 什么呢,一定很有意思。
Tony : 结果显示技术人员的特质包括如下几个方面,你不妨对对号,看看你说的是不是都在其中。
 a)管事
 b)管细
 c)非黑即白
 d)对事不对人
 e)科学
 f)量化
 g)古板
 h)关注过程
 i)收敛思维
Alex : 这么多呀,最后两条我好像没有说出来。
Tony : “不识庐山真面目,只缘身在此山中”亚(Tony微笑着说)。你没体会到的两点“关注过程”和“收敛思维”恰恰是我认为比较重要的两点,也是技术人员在转型道路上比较难克服的两点。这也是我所说的思维上的东西。
Alex : 刚才想了一下自己在平时工作中的行为,还真的能对上号。
Tony : 是呀。比如一个客户让一个开发人员去开发一个ftp客户端,他可能马上接受任务,然后马上开始想我该如何设计和实现这个ftp客户端,而把客户这个关键的任务搁置在一旁,收敛性的思维决定了他根本意思到需要和客户沟通,询问客户到底需要一个什么样的ftp客户端。
Alex : 真是说到我的心坎里了。
Tony : 我这里同时说说管理人员的特质,你不妨对比一下。管理人员具有和技术人员截然不同的特质,他们:
 a)管人
 b)管粗
 c)非黑非白
 d)对事又对人
 e)艺术
 f)概念化
 g)灵活
 h)关注结果
 i)发散思维
Alex : 有这么大的差别亚。
Tony : 不用担心,这个世界上99.99%的管理者都不是天生的,他们也是在工作实践中一点一滴地学习成才的。再给你讲这样的一件事情,你来看看如何去处理?如果你是一个部门的销售经理,你让你的一个下属去写一份“xx产品的市场调研报告”,他欣然领命后下去了,不过时间不长他就回来了,并向你询问“xx章节该如何去写”,这时候你应该如何做呢?
Alex : 难道我事先没跟他讲清楚么?
Tony : 你讲清楚了,而且他还频频点头,好像已经听懂了的样子,但是事实就是他又回来问你了,你知道为什么吗?
Alex :(疑惑…)那我可能会再详细的告诉他该如何去写。
Tony : OK,这个问题解决了,之后他又反复地回来问你一些其他的你认为已经给他讲清了的问题,你该如何去办呢?
Alex : 会发生这样的情况么?那还不如我自己写这个报告了,这样多烦亚。
Tony : (微笑)这是一个典型的技术人员转型的障碍之一–“亲历亲为”。这里还蕴涵着一个管理的技巧问题“如何进行工作分派”。
Alex : 这么复杂亚。
Tony : 前面不说过么管理是一门艺术。“亲历亲为”是技术人员在转型过程中最容易犯的问题。技术管理者在转型后常常抱怨每天“忙碌而无成效”,其中“亲历亲为”是一个重要的原因,当然不是唯一的。“亲历亲为”导致的最直接的后果就是你每天忙得焦头烂额,而你的staff member每天却清闲的很。你想想在工作中是不是常有这样的事情发生呢?
Alex : 嗯,的确如此。私下里和同事朋友吃饭聊天时总是能听到这样的抱怨。
Tony : 如何能做到不亲历亲为呢?给你讲一个我自己的故事,这个故事其实和上面的故事差不多,它发生在我的个人助理身上。一次要参加一个会议,我让我的个人助理帮我完成这篇演讲稿,她完成初稿后发给我让我审阅,我给她指出若干个错误,然她重新修改,如此反复不下20次,在一天之内,在我告诉我的那位助理演讲稿通过了时候,她都快哭了。之后我再让这位助理些稿子,总是一遍就通过,我再也找不出其中的不足了。你要知道如果我自己来完成那篇讲演稿的话,可能只需要我30分钟的时间,而我却花了大量的时间来纠正她的不足。不妨想像一下如果没有那次的反复纠正,那个助理永远也不知道什么样的稿子是合格的。从中你能体会到什么吗?
Alex : 嗯,有些感觉了。
Tony : 古语说“强将手下无弱兵”,在现代的工作中,这句话可未必百分之百正确。
Alex : 是呀,强将的“亲历亲为”导致了“弱兵”的诞生。
Tony : 在培养部下迅速成长的同时,还要留心一些技巧问题,就如第一个例子中讲的那个销售经理,他在分派工作时并没有掌握足够的技巧,导致了后来的结果。
Alex : 分派工作还需要什么技巧么,直接告诉他做什么不就可以了么?
Tony : 事实上并非如此简单,你回想一下上面的那些例子在你的平时工作中是否发生过?我相信一定有的。一般来说分派工作可以使用6步法:
一、要向你的下属解释这个任务的重要性;
二、应该告诉他改做些什么而不是如何去做;
三、明确他的权力范围
四、确定Deadline,这里注意给自己留好退路
五、听取反馈,最简单的方法就是让他当面复述一遍任务是什么。
六、剩下的就是控制和跟踪了。

Alex : 哇,真是不听不知道呀。
Tony : 呵呵,回去不妨试试,你会看到立竿见影的效果。

办公室电话响了….

Tony : Alex ,这次谈话就到这吧,回去总结思考一下,有空儿我们再聊。
Alex : Ok。

Alex起身出门,头脑中浮现出一个优秀管理者的形象。

CppUnit入门实践-Tony与Alex的对话系列

Tony : Hi Alex ! you just looks like drowing in your project. what is up?
Alex : 我们的项目要求引入单元测试,but i've no experience in unit test.
Tony : i think cppunit is your best choice.
Alex : 是的,我刚从网上把它down了下来,正准备研究它呢。
Tony : Really ? I have done some practice on unit test before. would you like me to join you?
Alex : Oh Tony, I'm so glad that you could help me !
Tony : My pleasue !
Alex : 我们从哪里开始呢?
Tony : The simplest case! 我们拿一个最简单的例子吧。now we have a class with the name "SimpleCalculator" and it has four basic methods 'add', 'sub', 'mul' and 'div', All we should do is to test whether these methods run as same as we expect. First of all , complete the "SimpleCalculator" class, Alex.
Alex : It is simple!

//SimpleCalculator.h
class SimpleCalculator{
 public :
  int add(int a, int b);
  int sub(int a, int b);
  int mul(int a, int b);
  int div(int a, int b);
};

//SimpleCalculator.cpp
int SimpleCalculator::add(int a, int b){
 return a+b;
}

int SimpleCalculator::sub(int a, int b){
 return a-b;
}

int SimpleCalculator::mul(int a, int b){
 return a*b;
}

int SimpleCalculator::div(int a, int b){
 return a/b;
}

Alex : 这里简单点,div方法没有考虑0作除数的异常情况。
Tony : 可以。还记得我上次讲的测试驱动开发么,不过今天我们不是用它,我们只做些简单的东西,目的就是为了熟悉工具的使用。
Alex : 那我们是不是也应该列出一个test case的list亚?
Tony : 没错。
Alex : 我来随意写几个吧。“add(5,6) == 11” 、“sub(5,6)==-1”、“mul(5,6) == 30”和“div(12,6) == 2”。
Tony : 然后我们一起来学习一下CppUnit的帮助文档吧。

(Tony and Alex are reading the doc of cppunit.)

Tony : 学到了些什么?
Alex : 看来这些xUnit框架的测试工具在概念上几乎是一致的,像TestCase、TestFixture和TestSuite这些概念都大同小异。
Tony : 不错,单元测试在于测试思想,工具只是个必要条件而已,工具并不能决定你的测试就是一个好的测试。下面你就按你理解的CppUnit去做吧。

Alex : Ok. 按照书中所说,我们一次要测试多个method,最好使用TestFixture。我是这样写的,你看看。

#include "SimpleCalculator.h"
#include "CppUnit/TestCase.h"
#include "CppUnit/TestResult.h"
#include "CppUnit/TextOutputter.h"
#include "CppUnit/TestResultCollector.h"
#include "CppUnit/TestCaller.h"
#include "CppUnit/extensions/HelperMacros.h"

class SimpleCalcTest : public CPPUNIT_NS::TestFixture{
private :
 SimpleCalculator * sc;

public:
 virtual void setUp(){
         sc = new SimpleCalculator();
     }
     virtual void tearDown(){
         delete sc;  
     }
 
 void testAdd(){       
         CPPUNIT_ASSERT_EQUAL( sc->add(5,6), 11);
     }

 void testSub(){       
         CPPUNIT_ASSERT_EQUAL( sc->sub(5,6), -1 );
     }

     void testMul(){       
         CPPUNIT_ASSERT_EQUAL( sc->mul(5,6), 30 );
     }

 void testDiv(){       
         CPPUNIT_ASSERT_EQUAL( sc->div(12,6), 2 );
     }
};

我们的主函数如下:
int main()
{
    CPPUNIT_NS::TestResult r;
    CPPUNIT_NS::TestResultCollector result;
    r.addListener( &result );

    CPPUNIT_NS::TestCaller testCase1( "testAdd", &SimpleCalcTest::testAdd );
    CPPUNIT_NS::TestCaller testCase2( "testSub", &SimpleCalcTest::testSub );
    CPPUNIT_NS::TestCaller testCase3( "testMul", &SimpleCalcTest::testMul );
    CPPUNIT_NS::TestCaller testCase4( "testDiv", &SimpleCalcTest::testDiv );
   
    testCase1.run( &r );
    testCase2.run( &r );
    testCase3.run( &r );
    testCase4.run( &r );
   
    CPPUNIT_NS::TextOutputter out( &result, std::cout );
    out.write();
    return 0;
}

Tony : 我觉得可行。运行一下,看看如何。
Alex : 输出结果如下:
OK (4 tests)

Tony : 这的确是一种可行的办法,不过你回想一下我们一起学习的doc中的内容,看看是否还有改进的余地了。现在如果你要在SimpleCalcTest类中加一个测试用例方法,不仅仅SimpleCalcTest要修改,我们的main函数也需要修改,还记得JUnit中有什么概念来支持么?

Alex : 你不提我还真的记不起来了,JUnit中有TestSuite,刚才在cppunit doc中我也看到了suite方法,也许会帮得上忙,稍等一下我再翻翻文档….

Alex : 我找到了。的确有更为简单的方法。我修改一下,引用的头文件不变。

class SimpleCalcTest : public CPPUNIT_NS::TestFixture{

    CPPUNIT_TEST_SUITE( SimpleCalcTest );
        CPPUNIT_TEST( testAdd );
        CPPUNIT_TEST( testSub );
        CPPUNIT_TEST( testMul);
        CPPUNIT_TEST( testDiv );       
    CPPUNIT_TEST_SUITE_END();

private :
 SimpleCalculator * sc;

public:
 virtual void setUp(){
         sc = new SimpleCalculator();
     }
     virtual void tearDown(){
         delete sc;  
     }
 
 void testAdd(){       
         CPPUNIT_ASSERT_EQUAL( sc->add(5,6), 11);
     }

 void testSub(){       
         CPPUNIT_ASSERT_EQUAL( sc->sub(5,6), -1 );
     }

     void testMul(){       
         CPPUNIT_ASSERT_EQUAL( sc->mul(5,6), 30 );
     }

 void testDiv(){       
         CPPUNIT_ASSERT_EQUAL( sc->div(12,6), 2 );
     }
};

CPPUNIT_TEST_SUITE_REGISTRATION( SimpleCalcTest );

主函数修改后如下:
int main()
{
    CPPUNIT_NS::TestResult r;
    CPPUNIT_NS::TestResultCollector result;
    r.addListener( &result );

    CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest()->run( &r );
    CPPUNIT_NS::TextOutputter out( &result, std::cout );
    out.write();
    return 0;
}

CppUnit利用宏来解决Suite的问题。在你的TestCase定义里面写入如下的这段代码:
CPPUNIT_TEST_SUITE( YourTestCase );
        CPPUNIT_TEST( testXX);
   …//
CPPUNIT_TEST_SUITE_END();
这段代码实际上是定义了一个函数suite,这个函数返回了一个包含了所有CPPUNIT_TEST定义的测试用例的一个测试集。CPPUNIT_TEST_SUITE_REGISTRATION通过静态注册把这个测试集注册到全局的测试树中,最后通过CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest()生成一个包含所有测试用例的测试并且运行。这样的话,一旦要添加新的测试用例函数,我们只需要修改SimpleCalcTest类即可。

Tony : Well done! Alex你独立解决问题的能力越来越强了。相信做到这你已经心里有底儿了,再往后就是在你的实际项目中摸索CppUnit的使用经验了。

Alex : 呵呵。谢谢夸奖!

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats