https://www.businessweekly.com.tw/careers/blog/3004708
緯創事件點出印度管理問題,鴻海等台廠如何克服挑戰?
緯創位於印度的 Narasapura 廠上週發生暴動事件,震驚業界。事件發生後,緯創現已解僱印度高級業務主管,同時重組團隊,並設立 24 小時的電話供員工匿名投訴。此次事件,雖說因工資爭議而引起,卻同時點出台廠在印度製造所面臨的「種姓制度」管理難題。
種姓制度是超級管理難題
緯創位在印度卡納塔卡省的 Narasapura 廠發生暴動,起因主要是工資爭議,有部分工人沒有按時得到報酬或獲得適當酬勞;然而,階級分明的種姓管理制度,或許才是本次暴動的潛藏禍根。印度「種姓」社會制度階級分明,社會地位低落的工人容易與管理人產生矛盾。
根據香港經濟日報報導,台灣企業在各國經營時,為了融入當地環境維持長期經營,多會推動人事在地化的策略。但是,印度的種姓制度,往往使得台商在實踐本土化管理時,要更小心處理階級問題;避免高階級的主管與低階級的員工出現矛盾或衝突。
對此,供應鏈人士也透露,台灣主管向來較常採用「搏感情」方式,與工人一起用餐、一起同歡,主管與工人間的階級沒有那麼明顯,做法也比較平等。但隨著在地化成趨勢,台灣製造廠開始聘用在地主管;由於印度有種姓制度,所以印度高階主管上任後,往往會一改過去台灣主管的平等作法或人事、勞務安排。這或許是緯創本次發生暴動的主要因素之一,使原本在緯創工作或已與緯創簽訂合約的勞務公司受影響,種下不滿因素。
也因此當地警方同時也在調查,是否有人為了宣洩不滿,鼓動基層工人暴動砸廠;卡納塔卡省工業廳長也表示,這起暴力事件可能是緯創與勞務公司和工人之間溝通不良所致。
如何管理維持穩定,女性員工或成一大關鍵
然而,緯創印度廠發生暴動後,並未影響台灣電子製造業者前進印度的計畫。像是和碩表示,大趨勢不受影響,會按先前規劃,印度廠最快明年下半年量產。鴻海也稱清奈擴產進度不會受此事件影響,同時鴻海與集團旗下富智康持續向印度政府申請生產獎勵。
這些持續實施印度製造策略的業者,究竟該如何因應種姓制度,維持管理、營運穩定?或許,鴻海去年已先實施關鍵策略,就是以女性員工為主。
2015 年,鴻海集團旗下富士康首座印度廠在印度安德拉省斯里市(Sri City)啟用;富士康印度工廠聘用將近 1.5 萬名勞工,女性約占九成,為多家公司組裝手機。第二座印度手機廠 2017 年在泰米爾納德省的斯利柏倫菩德(Sriperumbudur)開張,距第一座廠約 2 小時車程;這座廠聘用 1.2 萬人,廠房作業局部自動化。
在印度主管 Josh Foulger 領導下,印度富士康已成為重要的製造基地,未來也持續有擴廠計畫。那麼,為何會選擇以女性員工為主?Foulger 表示,事實上,他打從一開始就決定聘用女性勞工,因為執教鞭的母親說服他給婦女機會。
Foulger 透露,在印度,工廠女工不像中國那麼常見,鄉村婦女往往無酬做家事或進行農務;原本安德拉省斯里市甚至禁止女性輪值工廠夜班,直到當地政府和法院介入才改變;同時,也由於印度製造商大多偏好僱用男性,所以很輕鬆就達到招聘目標。
Foulger 強調,儘管必須增加保全、接駁巴士、宿舍等開銷,但這一切很值得,因為女性員工對獲得工作機會十分知足感恩,所以工作都十分賣力;同時多數印度女性工作時,心中都會有具體目標,像是償還家裡債務、讓小孩上更好學校等。
雖然此作法不能說是克服種姓制度的唯一解方,但鴻海印度廠以女性員工為主的特色,確實在營運管理保持一定穩定,並有利於未來擴產計畫;或許緯創事件發生後,此策略能供日後前進印度製造的台廠參考。
Progressive Web App 會是未來趨勢嗎?
https://blog.techbridge.cc/2016/07/23/progressive-web-app/
何謂 Progressive Web App (PWA)
先講結論,Progressive Web App 是希望能夠讓 Web application 盡可能的在各種環境(網路環境、手機作業系統等)下都能順暢且不減功能性的運作,並讓你的 Web App 可以:
- 直接被使用者安裝到桌面
- offline 使用
- 擁有推播功能
- 開啟時看不到 URL Bar(類 Native app 的使用經驗)
- 開啟時有 Splash Screen
而要做到這些事情,整個 PWA 的設計要點就會包含以下特性:
Progressive - 漸進增強:在越完善的環境下,能執行更加完整的服務,若環境不許可,能夠優雅降級,運行最基本的功能。
Responsive - 響應式介面:能夠在各種螢幕尺寸下顯示、能夠因應多種輸入方式與設備回饋(震動、音頻等)。
App-like - 類原生程式的操作模式與使用者介面:採用原生平台(Native App)的 Style 與資料更新方式(利用 service worker 存取快取資源)。
Fresh - 持續更新:使用 Service worker API 來自動更新應用程式(無需透過 App store, Google Play 等)。
Safe - 應全面採用 HTTPS 提供最基本的安全防護。
Discoverable - 透過設置 manifest 檔案,一樣能進行 SEO 優化,讓搜尋引擎找得到你的 APP。
Re-engageable - 透過推播,能主動與使用者互動。
Installable - 可安裝:透過 Add To Home 等方式,將 Web App 放在手機桌面,並且能在應用程式中單獨列出與切換,就像一般的 App 一樣,但完全不用透過應用程式商店下載。
Linkable - 透過 URL 可以隨時分享你的 App。
上面是官網所列出的,而紅色是我認為較為重點的特徵,而在這些重點特徵下,最大要點就是 Service worker。有了 Service worker 的幫助,你可以實作出離線可用的 Web App,讓 User 操作起來有更佳的使用體驗。
iOS 中 UITableView 和 自定義 UITableViewCell 的使用方法
使用纯代码自定义UItableviewcell实现一个简单的微博界面布局:https://www.cnblogs.com/wendingding/p/3761730.html
https://www.youtube.com/watch?v=2rd0FKN9XH8&list=PLzKtnppOmiXAYGqXEU_owKS-TH6FEZYeE&index=79
https://www.jianshu.com/p/f30eab24401f 頁庫存檔:
本文的重点并不仅是UITableView的基本使用方法,而是强调有关UITableView和UITableViewCell开发过程中的一些具体细节问题。基本信息请参阅Apple开发文档《Table View Programming Guide for iOS》。
概述
Table可能是最擅长于展示数据的一种UI部件。因此UITableView这个类是iOS App开发中除button和Label之外最常用的控件类型。几乎任何一个App都离不开tableView。使用UITableView很简单,核心就是要实现两个protocol。这是由于tableView在MVC中只是V这一环,所以它需要额外的支持提供另外的MC两个环节的功能才能让一个table完整的工作。而这种支持实现的途径就是protocol,Apple要求开发者提供实现** UITableViewDataSource** 和UITableViewDelegate 这两个protocol的支持类来协同对应的UITableView的工作。一般情况下,实现delegate protocol的类是UITableViewController,而data source protocol 可以是controller负责,也可以是其他helper类完成。但更多情况下,我更倾向于单独的modal wrapper类来完成。现在很多的建议data source尽可能不要放在controller中,这样有利于解决mass controller的问题。可以参考objc.io这篇文章:《Lighter View Controllers》
鉴于UITableView是如此的重要,iOS替我们定制化了两种类型的tableView:static和dynamic。前者适用于表格内容相对固定的场景,更多的使用在诸如Setting panel,Detail panel的地方;而后者适用于表格内容不固定,行数动态变化的场景,更多的使用在网络请求返回后,将动态的数据进行内容展示等。虽然Apple内置了几种(确切的说到目前为止是4种)table的style,但是对于App开发而言,大多数情况下都需要自行定制table对数据的展示方式,因此相对应的,table cell的定制化成为App开发的必修课题。
那么下文将介绍一下Static table的使用中需要注意的一些地方和dynamic table中cell开发的方法总结。
关于Static Table的报错
static table的设置方法很简单,在Xcode中设置UITableView的类型为static即可。
这里着重强调一个问题,绝大多数使用static table view的人都会遇到xcode报出的一个莫名其妙的错误:
error.png
而这个问题的原因是:放置static table的View Controller <u> ** 必须为iOS内置的UITableViewController类型 ** </u>
据说这是xcode的一个bug,但是到目前为止还没有被“修复”的迹象,总而言之,造成的结果就是,如果你想在某个页面放置一个static table view,你必须单独放在UITableViewController中,而且仅仅手动将自己的viewController的类继承自UITableViewController或者在xib中强制改成UITableViewController都不行,必须是原生的UITableViewController。可是很多情况下我们确实需要在自己的viewcontroller中添加一个static table view。怎么办?解决方法是使用Container View。
在你自己的ViewController中拖入一个Container View
删除这个Container View自动创建的segue和对应的target view controller
containerView.png
拖入一个新的UITableViewController,加入一个table view,修改类型为static;
Ctrl-drag container view到这个UITableViewController,在弹出的segue类型中选择Embed:
statictable.gif
当然,这种方式只适用于storyboard操作并且要求支持Container VC的iOS版本。在其他情况下,可以直接使用addSubView:,将UITableViewController的view(当然就是tableView)加到自己的“container”view之下。
UITableViewCell的使用方法
下文的重点是总结UITableView和UITableViewCell的核心方法。更多详情可以参考Apple的官方文档。
1. 预定义Cell
iOS自定义了4种常见的Cell格式,在UITableViewCell.h中的注释中Apple给了一些明确的提示这些预置的style一般都适用于什么场景:
typedef enum {
UITableViewCellStyleDefault, // Simple cell with text label and optional image view (behavior of UITableViewCell in iPhoneOS 2.x)
UITableViewCellStyleValue1, // Left aligned label on left and right aligned label on right with blue text (Used in Settings)
UITableViewCellStyleValue2, // Right aligned label on left with blue text and left aligned label on right (Used in Phone/Contacts)
UITableViewCellStyleSubtitle // Left aligned label on top and left aligned label on bottom with gray text (Used in iPod).
} UITableViewCellStyle4种类型在Xcode中对应的选项为:Basic, Right Detail, Left Detail和Subtitle。在iOS8下测试,对应的示例图如下:
Basic:
Basic.png
Right Detail有图时:
rightdetail1.png
Right Detail无图时:
rightdetail2.png
Left Detail:
leftdetail.png
Subtitle:
subtitle.png
在这4种格式都统一有3个property可以供你使用:
textLabel:一个主标题
detailTextLabel:一个副标题
imageView:一张详情缩略图片
实际上这些预置类型就是把这3种元素做了些取舍然后在不同的位置组合了一下。我觉得在设计App的时候,在任何情况下,设计师和工程师都应当首先考虑这些预置的类型能不能满足需求,除非有足够的必要,否则不要轻易的浪费经历在重复构造定制化的View上。个人觉得Subtile模式已经适用于绝大多数对UI要求不高的场合。你完全可以自己修改这3个控件的一些属性来对UI进行微调。比如你可以尝试将imageView的大小放大一些。
2. 自定义Cell
UITableView是通过调用UITableViewDataSource中的tableView:cellForRowAtIndexPath:方法来获取每一行所需要的Cell的,所以绝大多自定义Cell的处理过程都是在这一步完成,另外由于UITableViewCell本身也是一个UIView,所以你也可以在UITableViewDelegate中的tableView:willDisplayCell:forRowAtIndexPath: 方法中对Cell的view做最后的定制化。
注意: Apple明确指出,在tableView:willDisplayCell:forRowAtIndexPath:中应当只修改“state-based properties”,比如selection和background color等等,但是不应该是内容(content),也就是不要在这里进行任何数据处理。
2.1 自定义Cell的创建
有以下几种方法:
方法1:使用Code继承预定义的cell样式,然后再手动添加自己的view
这是Apple官方文档中的示例,它通过调用initWithStyle:reuseIdentifier:使用UITableViewCellStyleDefault参数来创建一个Cell,为了方便期间,我对代码稍做了些改动,一个是简化了数据加载,另一个是用NSTextAlignment替换了废弃的UITextAlignment:
#define MAINLABEL_TAG 1
#define SECONDLABEL_TAG 2
#define PHOTO_TAG 3
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"ImageOnRightCell";
static int i = 0;
UILabel *mainLabel, *secondLabel;
UIImageView *photo;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
mainLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 220.0, 15.0)];
mainLabel.tag = MAINLABEL_TAG;
mainLabel.font = [UIFont systemFontOfSize:14.0];
mainLabel.textAlignment = NSTextAlignmentRight;
mainLabel.textColor = [UIColor blackColor];
mainLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
[cell.contentView addSubview:mainLabel];
secondLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 20.0, 220.0, 25.0)];
secondLabel.tag = SECONDLABEL_TAG;
secondLabel.font = [UIFont systemFontOfSize:12.0];
secondLabel.textAlignment = NSTextAlignmentRight;
secondLabel.textColor = [UIColor darkGrayColor];
secondLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
[cell.contentView addSubview:secondLabel];
photo = [[UIImageView alloc] initWithFrame:CGRectMake(225.0, 0.0, 80.0, 45.0)];
photo.tag = PHOTO_TAG;
photo.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
[cell.contentView addSubview:photo];
} else {
mainLabel = (UILabel *)[cell.contentView viewWithTag:MAINLABEL_TAG];
secondLabel = (UILabel *)[cell.contentView viewWithTag:SECONDLABEL_TAG];
photo = (UIImageView *)[cell.contentView viewWithTag:PHOTO_TAG];
}
mainLabel.text = [NSString stringWithFormat:@"Title_%d", i];
secondLabel.text = [NSString stringWithFormat:@"Description_%d", i];
i++;
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"jpg"];
photo.image = theImage;
return cell;
}最终效果如下:
CustomCell1.png
这里有两个重点:
Cell的重用机制
重用机制对于UITableView而言是非常重要的概念,这能够显著提高滑动TableView时的性能。如果不使用重用,那么每次新的Cell出现在屏幕上时都需要新创建一个,这对快速滑动而言是非常影响用户体验,并且会占用系统大量的内存开销。iOS的TableView使用的重用机制在原理上很简单,就是系统自动维护一个queue,这个队列放着一定数量的准备好的Cell UI object,滑出屏幕范围之外一定“距离”的Cell都会被回收到这个queue里,给马上要滑入屏幕范围内的Cell复用。
使用重用的方法核心是两个概念:Cell Identity和dequeue。前者是标识一种具体的Cell的id,后者是将Cell从复用队列中取出的实际操作。首先你需要用这个id告诉系统你将要用于重用的Cell是谁(注册),然后你使用这个id从重用的队列里取出来(复用)。具体到本例中的API就是如下两个:initWithStyle:reuseIdentifier:和dequeueReusableCellWithIdentifier:。后面将看到,对于不同情况下创建的Cell,注册和复用的调用也并不相同。
必须把自定义的控件添加在cell的contentView上,而不是view上,也就是:
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
...
// Correct!
[cell.contentView addSubview:yourCustomComponetView];
// Wrong!
// [cell.view addSubview:yourCustomComponentView];再次强调一点,Cell的Content View不是自己的root view。关于Cell View的结构可以参考这篇文章:《制作一个可以滑动操作的 Table View Cell》
这里只摘出最终结论,能够让你对一个Cell的view有直观的理解。
对于一个如图所示的Table而言:
sample.png
它的TableViewCell的View层级结构是:
<UITableViewCell; frame = (0 396; 320 44);> //1
| <UITableViewCellScrollView; frame = (0 0; 320 44); > //2
| | <UIButton; frame = (302 16; 8 12.5)> //3
| | | <UIImageView; frame = (0 0; 8 12.5);> //4
| | <UITableViewCellContentView; frame = (0 0; 287 44);> //5
| | | <UILabel; frame = (15 0; 270 43);> //6这个Cell 里有六个视图:
* UITableViewCell 这是最高层的视图。 Frame 显示它有 320 点宽和 44 点高——宽度和高度都和预期的一致,因为它和屏幕一样宽,而高度就是 44 点。
* UITableViewCellScrollView 虽然你不能直接使用这个私有类,但它的名字很好地暗示了它的功能。它的 Size 和 Cell 的一样。
* UIButton 它在 Cell 的最右边,就是 Disclosure Indicator 按钮。
* UIImageView 是上面 UIButton 的子视图,装载着 Disclosure Indicator 的图像。
* UITableViewCellContentView 另外一个私有类,它包含 Cell 的内容。这个类对于开发者来说就是 UITableViewCell 的 contentView 属性。但它只作为一个 UIView 来暴露在外,这就意味着你只在其上调用使用公开的 UIView 方法;而不能使用任何与这个类关联的任何私有方法。
* UILabel 显示 “Item #” 文本。
很显然,这里cell.contentView并不是cell.view。
方法2:使用xib绘制Custom Cell View
这是自定义Cell最常见也是最省力的方法:
首先在xcode中创建custom xib,拖拽需要的控件到xib上,并做好布局和限制;
2)新建自己的custom class,定义对应的outlet properties;
3)将xib的class设置成对应的custom class,然后将outlet和控件连接起来;
4)在适当的位置(一般为初始化的地方)调用registerNib:forCellReuseIdentifier:注册Cell;
5)在tableView:cellForRowAtIndexPath:中调用dequeueReusableCellWithIdentifier:forIndexPath:复用cell
下面的这个示例演示了上述步骤。在这个示例中,首先创建Custom Cell和xib的界面,其中有一张大图,下面有两个独立的label,然后我使用了tableView:willDisplayCell:forRowAtIndexPath:对每一行Cell的背景颜色做出最终设置,而在tableView cellForRowAtIndexPath:中对Cell的内容进行填充:
Custom View:
@interface MyTableCellView : UITableViewCell
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (weak, nonatomic) IBOutlet UILabel *name;
@property (weak, nonatomic) IBOutlet UILabel *date;
@endCustom Xib:
CustomXib.png
在table View Controller中:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup here ...
...
// register the cell to tell the system preparing to reuse it.
[self.tableView registerNib:[UINib nibWithNibName:@"TableCellView" bundle:nil] forCellReuseIdentifier:cellId];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// always reuse the cell
MyTableCellView *cell = [tableView dequeueReusableCellWithIdentifier:cellId forIndexPath:indexPath];
cell.frame = CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, 250);
NSString *path = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"jpg"];
cell.imageView.image = [UIImage imageWithContentsOfFile:path];
NSDate *object = self.objects[indexPath.row];
cell.date.text = [object description];
return cell;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"indexpath = %ld", indexPath.row);
if ( indexPath.row % 2 == 0) {
cell.backgroundColor = [UIColor redColor];
}
else {
cell.backgroundColor = [UIColor greenColor];
}
}Demo:
CustomCell2.png
方法3:使用code定义一个Custom Cell Class
这个在本质上和上一种使用xib的方法是一样的,只不过一个是用代码完全定制,一个是借助xib操作。但是在Cell重用的方式上有一定区别。上一种方法中,需要调用registerNib:forCellReuseIdentifier:来注册重用的Cell,在这里就需要用registerClass:forCellReuseIdentifier:方法来注册。与之对应的,获取重用的Cell的时候,调用dequeueReusableCellWithIdentifier:forIndexPath:方法。
Class myClass = [MyTableCellView class];
[self.tableView registerClass: myClass forCellReuseIdentifier:@"CustomCell"];
...
...
MyTableCellView *cell = [self.tableView dequeueReusableCellWithIdentifier:@"CustomCell" forIndexPath:path];
cell.label.text = @"text";
...注意 dequeueReusableCellWithIdentifier:和dequeueReusableCellWithIdentifier:forIndexPath:的区别!!
如果你注册过Cell,在没有可用的cell时,前者会返回nil;而后者永远都会从注册的nib或者class中替你创建一个可用的Cell。也就是说,前者调用你需要手动检查nil,而后者不需要;
如果你从没有注册过cell,在没有可用的cell时,前者会返回nil,后者……直接崩溃!也就是说,调用后者你 必须确保注册过cell 。
2.2 访问Cell中的控件:
xib中使用outlet
这个应该不用多说,在Cell的原型中(不管是Static cell还是Dynamic cell)定义outlet properties,然后在xib中拖拽连接对应的控件即可;Apple官方文档上的示意图:
connect_outlet.jpg
connect_static_objects.jpg
代码中使用viewWithTag:
这个是获取parent view上某个特定view的快捷方法,首先需要设置一个sub view的tag,然后使用viewWithTag:来访问这个sub view。设置时可以通过xcode在xib中设置tag标签,也可以直接通过tag property手动设置:
创建时:
mainLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 220.0, 15.0)];
mainLabel.tag = MAINLABEL_TAG;
// customize the label here...
[cell.contentView addSubview:mainLabel];访问时:
mainLabel = (UILabel *)[cell.contentView viewWithTag:MAINLABEL_TAG];有关Table和Cell的性能需要注意的问题
关于这个话题,Apple并没有用过多的篇幅介绍,但是在官方开发文档中明确提出了3点意见:
注意重用(Reuse Cell)
这点我们已经在上文中着重强调过了。
避免反复的调整Cell的布局(Avoid relayout of content)
只在创建每一个Cell的时候布局一次,而不要每一次获取Cell的时候都去重新布局。
避免透明的subviews (Use opaque subviews)
自定义cell的时候,尽可能避免使用透明的控件,因为透明控件在table滑动时将增大渲染开销。
总结
本文主要从Static table和Dynamic table两方面总结了UITableView和UITableViewCell的核心使用方法和问题,并着重介绍了Custom Cell的几种方法和注意事项。
另外,有兴趣的话,UITableView还有另外几个比较关键的功能可以继续研究,一个是Editing mode,一个是Table Index,还有一个相对也很重要的功能自定义Header和Footer View。有空的话可以再总结一下。希望此篇能帮助到您。
2016年4月5日,完稿于南京。
團隊如果有一兩個人能力僅勉強勝任的話,會拉低團隊所有人的表現
1.Netflix 創辦人海斯汀透過一場「關鍵裁員」,透析組織氣氛經營與人才篩選提高人才密度,對於Netflix的關鍵影響。
2.懶鬼、討厭鬼、憂鬱消極鬼,當團隊中出現這三種人,不論再優秀的團隊,其他成員也會被單一特定人士的行為影響,因而嚴重拖累團隊表現。
2001年春天,危機來襲。第一波網路泡沫破滅,無數網路公司倒閉消失。所有創投基金都中止了。我們一夕之間籌不到公司運作需要的周轉資金,而我們的公司又遠稱不上賺錢。公司士氣低迷,而且即將再往下挫,因為我們必須解雇1/3的員工。
我找馬克和派蒂.麥考德(Patty McCord)坐下來商量——派蒂是從Pure Software跟著我過來的同事,當時擔任人資長。我們仔細審核每一名員工的貢獻。沒有誰表現明顯特別差。所以我們把員工分成兩堆:80名表現最佳的員工,我們會留下;40名相較沒那麼出色的員工,我們會請他走。那些獨具創意、工作成績亮眼,而且與他人合作融洽的人,自然立刻分進「留下」那組。難是難在有很多介於及格邊緣的案例。有些人做同事做朋友都是好人,但工作表現平平。也有些人是工作狂,但判斷力不穩定,時常需要手把手地教。少數有幾個特別有才華,工作能力也強,但是愛抱怨或悲觀消極。這些人多半都得離開。可以想見,這個過程一點也不輕鬆。
我太太總說,宣布裁員前那幾天,我簡直如坐針氈。她說得沒錯,我擔心辦公室的士氣會盪到谷底。我深信在我打發了他們的朋友和同事以後,留下的人也會覺得公司待員工沒有誠信,所有人到時絕對都會很不滿。更何況「倖存者」還必須扛下離開的人的工作,可想而知一定會有很多抱怨。我們已經資金短缺,還承受得了士氣再瓦解嗎?
裁員的那一天到了,場面一如預期的難堪。被裁的人有的哭了,有的摔門,也有人氣得大吼大叫,到中午才告一段落。我則默默等待風暴進入下半場,也就是留下員工的反彈⋯⋯沒想到,除了幾許眼淚和明顯可見的悲傷之外,所有人都很平靜。接下來幾星期,氣氛大幅好轉,我一開始還不知道為什麼。我們依舊處於共體時艱的狀態,而且才剛裁了1/3員工,但辦公室卻突然活絡起來,迸發熱情、活力和創意。
幾個月後進入耶誕節假期,DVD播放機是那年熱銷的禮物。到了2002年初,我們的郵租DVD生意再度飛速成長。轉眼之間,我們的工作量翻升好幾倍——儘管員工數比之前少了1/3。令我驚奇的是,同樣是這80個人,他們處理所有工作的熱情似乎更勝以往。他們的工作時間拉長了,鬥志卻極高。不只是我們的員工變快樂,我早上醒來也等不及想去上班。那段日子,我每天順路載派蒂去公司,她也住聖克魯斯,每當我轉進她家門前,她幾乎都是雀躍地跳上車,臉上掛著大大的笑容說:「里德,這到底是怎麼回事?這就是戀愛的感覺嗎?難不成是某種化學作用,這種興奮感之後就會消退?」
派蒂講到了重點。整個辦公室感覺就像充滿了瘋狂愛上工作的人。
我不是在提倡裁員,而且也慶幸Netflix自此以後不必再做相同的事。但在2001年裁員風波之後那幾天,乃至於那幾個月,我發現了幾件事,徹底改變我對員工動力和領導責任的理解。我突然有所領悟,我對人才密度在組織中發揮的作用認知從此不同。我們從中學到的經驗,成為後來指引Netflix走向成功的基礎之一。
2001年裁員事件後,派蒂和我花了數十趟通勤車程討論這件事,想知道公司的工作氛圍怎會突然急轉彎向上,我們又該怎麼做,才能維持這股正向的動能。我們漸漸明白,我們的「人才密度」急遽提升,正是公司進步的推手。
優秀的人會幫助彼此進步更快
每位員工都具備某些才能。過去我們有120人的時候,有些員工才能出眾,另一些能力平平。總體來說,我們有相當的才能分散在全體人力之中。裁員以後,因為只留下最有能力的80個人,我們的才能總量減少了,平均每名員工的才能值卻提高了。因此,我們的才能「密度」提升了。
我們發現,人才格外密集的公司,也是人人都想效力的公司。高績效表現的員工在整體人才密度高的環境裡,尤其如魚得水。
我們的員工從彼此身上能學到更多,團隊的績效也更高。這又提升了個人的動力與滿足感,進而帶領公司整體實現更多成就。我們發現讓周圍環繞菁英,能讓原本已經不錯的成果彈射到全新境界。
最重要的是,與真正有才能的同事一起工作令人興奮、帶來鼓舞,而且充滿樂趣——相較過去只有80名員工,今日公司已有7000名員工也一樣。
我經由事後觀察發現,團隊如果有一兩個人能力僅勉強勝任的話,會拉低團隊所有人的表現。如果你的團隊有5名優秀下屬,另兩個差強人意,那這兩個勉強勝任的員工會:
耗盡主管心力,主管照顧優秀員工的時間減少。
降低團體討論品質,拉低團隊的總體智商。
迫使其他人必須養成另一套方法與他們共事,損害效率。
劣幣驅逐良幣,迫使追求卓越的人離職。
形同告訴團隊你能接受庸才,使問題更加複雜。
對優秀菁英來說,好的工作環境不在於辦公室裝潢鋪張、有漂亮健身房,或午餐有壽司吃到飽。身旁環繞有能力又懂得合作的人才,這些人又能幫助你變得更好,這種喜悅才是重點。當每個成員都很優秀,工作表現就會出現正向循環,員工能彼此學習、激發彼此的動力。
表現會傳染
你手下有平庸的人,會讓許多原本優秀的下屬也表現平庸。但若你的團隊全部由表現優異者組成,每個人都會激勵彼此做到更好。
澳洲新南威爾斯大學教授威爾.菲普斯(Will Felps)做過一項研究,結果令人驚奇,突顯了職場環境中行為的傳染力。他將大學生每4人一組,分成多組,請每組在45分鐘內完成一項經營管理任務。成效最好的一組可以獲得100美元獎金。
學生不知道,有些組內其實混入了演員,分別扮演以下幾種角色:「懶鬼」不參與討論,會把腳翹到桌上,傳簡訊和人聊天;「討厭鬼」會嘲諷挖苦,說些「你太扯了吧?」和「看來你根本沒上過商學課」之類的話;還有「憂鬱消極鬼」,臉上一副他家貓咪剛死掉的表情,抱怨任務做不到,質疑團隊不可能成功,有時還會乾脆趴在桌上。演員不會向其他組員透漏身分,其他人以為他們是一般學生。
菲普斯教授首先發現,即使小組中其他組員特別聰明又有能力,但一個人的不良行為仍會拉低全組的效率。這一個多月的時間,他進行了數十次試驗,組內有不良成員的組別,表現比其他組整整差了3成到4成。
這些發現顛覆了幾十年的研究,過去的研究多認為,團體內的個人會屈從團體的價值觀和行為準則。但事實卻是,某一個人的行為會快速感染團體其他成員,即使團隊才相處45分鐘。
菲普斯教授解釋:「令人驚訝且不解的是,團隊中的其他人為什麼會開始出現那個人的特質。」假冒者是懶鬼的時候,組內其他人也會對企劃失去興趣,最後總會有人跳出來宣稱任務其實也沒那麼重要。演員扮演討厭鬼,組內其他人也會開始互相羞辱,話中帶刺。演員如果是憂鬱消極鬼,影響最明顯。菲普斯說:我還記得我看到其中一組的影片。一開始所有組員都坐得直挺挺的,活力充沛,等不及想挑戰這個可能有難度的任務。但是到後來,每個人姿勢都垮了,頭都趴在桌上。」
菲普斯教授用實例說明了我和派蒂在2001年學到的事。團隊裡即使只有少數表現平庸的人,他們的表現仍有可能傳染給其他人,拉低整個組織的表現。
我們大多數人應該都能想起人生中有過的類似時刻,親眼目睹這種行為感染法則上演,我12歲時就見過一次。
我1960年出生在麻州。小時候的我很平凡,沒什麼特殊才華或出眾能力。小學3年級時,我們全家搬到華盛頓特區,生活過得還不錯,我也有一大群朋友。但到了6、7年級的時候,學校有一個叫凱文的同學,會聚集大家打架。他也沒有特別針對或霸凌我們之中的誰。他多數時候並不起眼,卻創造出一種行為模式,連帶影響了我們其他人的行為表現和相處方式。我很不想加入,但不參與打架感覺會比湊一腳還要丟臉。而且誰打輸、誰打贏,真的會決定大家一整天的氛圍。要是沒有凱文,我們彼此互動和一起玩的方式一定會大有不同。因此當我爸告訴我們要搬回麻州的時候,我簡直等不及立刻就走。
2001年裁員後,我們才發覺原本在Netflix裡,也有一小群人成就了令人不愉快的工作氣氛。從數不清的小地方看得出很多人不適任他們的工作,看在其他人眼裡則暗示公司可以接受平庸的表現,長久下來,就拉低了每個人的表現。
2002年,我們對於優良的職場需要具備的條件有了更多認識,我和派蒂立下承諾,我們往後的首要目標,就是要盡一切所能維持裁員後的人才密度,以及隨之而來的所有優點。今後我們會雇用最優秀的員工,支付業界最高的薪水。我們會訓練主管拿出勇氣和紀律,凡有不適任的行為或表現未達模範標準的員工一律裁除。我開始嚴格檢視,從接待櫃檯到最高執行團隊,確保Netflix的員工都是業界表現最佳、合作能力最強的人才。
iOS 開發:去除頭尾空白、去除特殊符號
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:@"/@/:;()¥「」/"、[]{}#%-*+=_\\|~<>$€^•’@#$%^&*()_+’\""];
NSString *trimmedString = [city.text stringByTrimmingCharactersInSet:set];
NSString *str = [textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSUInteger len = 0;
len = [trimmedString length];iOS 開發:字符串去掉特殊字符(只保留大小寫英文字母和數字)
https://www.jianshu.com/p/082d3739f5db
調用 removeSpecialCharacters 方法
- (NSString *)removeSpecialCharacters:(NSString *)value{ NSMutableString *string = [NSMutableString stringWithString:value]; unichar c; for(int i=0;i<string.length;i++){ c = [string characterAtIndex:i]; if(![self charIsNum:c]){ //First determine if it is a number. If it is not a number, continue to determine whether it is a letter. if(![self charIsZimu:c]){ //If it is not a letter, it means neither a number nor a letter NSString *str = [NSString stringWithCharacters:&c length:1]; NSLog(@" removeSpecialCharacters str=%@",str); NSRange range = NSMakeRange(i, 1); [string deleteCharactersInRange:range]; --i; } } } NSString *newstr = [NSString stringWithString:string]; NSLog(@" removeSpecialCharacters after str=%@",newstr); return newstr; } //Judging whether it is a number -(BOOL)charIsNum:(unichar)chars{ if(isdigit(chars)){ return YES; } else { return NO; } } //Determine if it is a letter -(BOOL)charIsZimu:(unichar)chars{ if((chars<'A'||chars>'Z')&&(chars<'a'||chars>'z')) { return NO; } else { return YES; } }
- (NSString *)removeSpecialCharacters:(NSString *)value{
NSMutableString *string = [NSMutableString stringWithString:value];
unichar c;
for(int i=0;i<string.length;i++){
c = [string characterAtIndex:i];
if(![self charIsNum:c]){
//First determine if it is a number. If it is not a number, continue to determine whether it is a letter.
if(![self charIsZimu:c]){
//If it is not a letter, it means neither a number nor a letter
NSString *str = [NSString stringWithCharacters:&c length:1];
NSLog(@" removeSpecialCharacters str=%@",str);
NSRange range = NSMakeRange(i, 1);
[string deleteCharactersInRange:range];
--i;
}
}
}
NSString *newstr = [NSString stringWithString:string];
NSLog(@" removeSpecialCharacters after str=%@",newstr);
return newstr;
}
//Judging whether it is a number
-(BOOL)charIsNum:(unichar)chars{
if(isdigit(chars)){
return YES;
}
else {
return NO;
}
}
//Determine if it is a letter
-(BOOL)charIsZimu:(unichar)chars{
if((chars<'A'||chars>'Z')&&(chars<'a'||chars>'z'))
{
return NO;
}
else {
return YES;
}
}
訂閱:
文章 (Atom)
程式語言編年史
程式語言編年史原文 下面這張圖片描繪了整個程式語言的歷史。包括各種程式語言的發明人、程式語言的特點和適用領域、被什麼網站或公司使用等 (檢視 完整高清圖 )。 之所以會有那麼多不同的程式語言是因為設計程式語言的初衷不同、對語言學習曲線的追求不同、不同程式之間的執行成本差異...













