שמירה על סדר מיון בFLEX DataGrid

בעייה מעצבנת שקוראת בDataGrid של פלקס. כאשר ממיינים לפי עמודה ולאחר מכן מחליפים את הDataProvider, הסדר לא נשמר. כלומר המיון מתבצע רק בלחיצה על הכותרת אבל לא מתבצע שוב כשהprivder משתנה (מוחלף ליתר דיוק). כדי לעקוף זאת, כתבתי class נחמד שיורש מDataGrid ומטפל בבעייה. להלן הקוד:


package il.co.j2ee.samples {
import mx.controls.DataGrid;
import mx.events.CollectionEvent;
import mx.events.DataGridEvent;
import mx.events.FlexEvent;

public class SortedDataGrid extends DataGrid {
 private var lastSortingEvent:DataGridEvent;

 public function SortedDataGrid() {
 super();
 addEventListener("headerRelease", onHeaderRelease);
 }

 public override function set dataProvider(data:Object):void{
 super.dataProvider = data;
 addEventListener(CollectionEvent.COLLECTION_CHANGE, onDataChange);
 }

 private function onHeaderRelease(event:DataGridEvent):void{
 lastSortingEvent = event;
 }

 private function onDataChange(event:CollectionEvent):void{
 if (lastSortingEvent){
 dispatchEvent(lastSortingEvent);
 }
 }

}
}

כך זה נראה במקור:

וכך לאחר השימוש בSortedDataGrid:

שליטה על כפתורי הדפדפן (Browser) בFLEX

לעיתים, יש צורך למנוע מהמשתמש לצאת מהאפליקציה בו הוא נמצא או להזהיר אותו כשהוא עומד לעזוב את הדף. הבעיה שבפלקס דברים רבים נשמרים בClient ומשתמשים לא תמיד מודעים לכך שסגירת הדפדפן עלול להביא לאיבוד מידע. הקוד הבא מדגים כיצד ניתן להזהיר את המשתמש בעת לחיצה על Back, Forward, Refresh או סגירת הדפדפן (או הלשונית).

הקוד מבוסס ג'אווה סקריפט (JS) ויכול לשמש גם באפליקציות WEB רגילות.

הערה: הקוד נבדק ונמצא תומך על הדפדפנים הבאים:

  • IE 7 ומעלה
  • FireFox
  • Chrome

קוד הJavaScript שיש לכלול בדף שעוטף את הSWF:


<script type="text/javascript">
 var url = window.location;
 window.onhashchange = locationHashChanged;

 window.onbeforeunload = function(){
 return "All unsaved changes will be lost"
 }

 function locationHashChanged(){
 var currentUrl = window.location.href;
 if (currentUrl.indexOf('#c') == -1){
 var answer = confirm("Are you sure you want to leave this page? All unsave changes will be lost");
 if (answer){
 history.go(-1);
 }
 else{
 window.location = url+"#c";
 }
 }
 }

 </script>

דוגמא מלאה אפשר לראות כאן

סוד ההצלחה של ABAP ושל SAP ERP

מה זה ABAP?

ABAP הינה שפה פנימית של חברת SAP המשמשת לפיתוח אפליקציות עסקיות בתוך מערכת הERP. השפה משמשת אך ורק בתוך מערכת הSAP ואי אפשר לכתוב תוכניות ABAP מחוץ למערכות SAP. השפה פותחה בשנות ה80 ונחשבת מיושנת מבחינת סינטקס (מזכירה קצת את קובול).

כבר שנים מתכנתים רבים נוטים לזלזל בשפה ולחשוב עליה כמיושנת. למי שרגיל לכתוב בשפות בסגנון C כמו: C,C++,Java,C# קשה להתרגל לפקודות ולסינטקס השונה. בנוסף, העובדה שרק לאחרונה נוספה תמיכה בOOP ושרק מעטים משתמשים באופציה זו הינה עוד פקטור שהופך את השפה לפרימיטיבית.

מצד שני, הלקוחות עובדים שנים רבות עם השפה ומרוצים ממנה באופן כללי. למעשה היא נותנת מענה מצוין לכתיבת אפליקציות עסקיות והתוצאות מהירות וטובות יותר מאשר בכל שפה אחרת כולל פלטפורמות מודרניות כמו Java או .NET מה הופך את ABAP לכזה סיפור הצלחה? כיצד קרה שמרבית הטרנזקציות העסקיות בעולם עוברות דרך שפה זו ובעולם ממשיכים לפתח בה ללא הפסקה? להלן 7 סיבות להצלחת השפה

אינטגרציה מלאה

כשמתכנת כותב בשפה כלשהי הוא משתמש בכמה מוצרי תוכנה: שרת אפליקציות, סביבת פיתוח, סביבת הרצה, בסיס נתונים, מערכת ניהול גרסאות ולעיתים עוד כמה תוכנות. האינטגרציה בין התוכנות השונות גם כשהן מגיעות מאותו ספק (מיקרוסופט למשל) גוזלת זמן ומשאבים. ABAP רצה בתוך מערכת הSAP כך שאין צורך אפילו בסביבת פיתוח (הקליינט של SAP הוא הסביבת פיתוח). נכנסים למערכת, טוענים את התוכנית ומתחילים לקודד.

אין הפרדה בין השכבות

כיוון שהDB הוא חלק ממערכת הSAP, וכך גם הקליינט, אין למעשה הפרדה בין שכבת הUI לשכבת הדאטה וללוגיקה. בABAP אין מודלים של MVC ואין ORM או שכבות DAL. אתה רוצה לכתוב לטבלה? השפה עצמה "מכירה" את כל הטבלאות והמבנים של המערכת ואין צורך להתחבר דרך ממשק כלשהו כפי שנעשה בדוט נט (ADO) או בג'אווה (JDCB). הGUI הוא אחיד ורץ בקליינט של SAP. לא צריך לדאוג לתמיכה בדפדפנים או להתנהגות של אלמנטים שונים בHTML.

אין Client-Server

טוב, זה לא שבאמת את קליינט סרבר אבל מבחינת המתכנת אין משמעות למה שרץ בצד השרת ומה רץ בצד הקליינט. חיברת ListBox לרשימה עם 40,000 פריטים? אין בעיה. SAP תדאג להציג את זה בצורה האופטימלית עם או בלי דפדוף והכל ינגן כמו שצריך.

אין שפות סקריפט שרצות בדפדפן, אין ניהול של sessions וcookies ולא צריך לדאוג לstate של התוכנית.

אין ריבוי משתמשים

כמובן שיש ריבוי משתמשים אבל מבחינת המתכנת הוא רץ ב"עולם" משלו והוא מסתכל רק על המשתמש שכרגע logged in.

מוגבלות זה כוח

בABAP אין ספריות native. אי אפשר לפתח API בABAP שיתממשק לפייסבוק וישלח הודעות לטוויטר. השפה נועדה רק לתוכניות עסקיות וככזו היא מוגבלת לסט הפקודות שSAP מספקת. החיסרון הוא שאי אפשר למשל לפתח רכיבי UI חדשים ותוכניות SAP תמיד ייראו באותו סגנון. מצד שני, מי בכלל צריך את זה? למה שמנהל לוגיסטי ירצה פתאום לשלב את חדשות מזג האוויר של Yahoo בתוך אפליקציית ניהול המחסנים שלו? המסכים הסטנדרטים מספקים כל מה שצריך בשביל העבודה והעובדה שאין אפשרות להכניס טכנולוגיות מבחוץ (למעט קוד ABAP אחר) מבטיחים יציבות ופשטות.

תכנות פרוצדוראלי

מסיבה כלשהי, כנראה שלמוח האנושי יותר קל לחשוב בצורה של פרוצדורות/פונקציות מאשר בצורה של OO ואובייקטים. אני נתקל במיישמים רבים שמדברים על טבלאות ושדות והפעלה של פונקציות אבל כשמדברים איתם על הורשה לא מבינים מה רוצים מהם. אמנם כיום יש OO ABAP אבל רוב תוכניות הABAP כתובות בצורה המסורתית של פונקציות וזה בסדר גמור. היישויות בABAP הם לרוב מבנים שקיימים בתוך מערכת הSAP ודומות לstruct שמכיל נתונים אך לא פונקציות. הפונקציות בABAP יכולות לקבל טבלאות כפרמטרים ולהחזיר טבלאות בהתאם אך הפונקציות לא שייכות לישויות עצמן כמו בOO.

סטנדרטים קשוחים לניהול קוד

מערכות SAP דורשות סטנדרטים קבועים בכל מה שקשור לשמות של פונקציות ועצמים, מתחמי שמות (name spaces), חבילות, ספריות וכו'. מהבחינה הזו, למתכנת ABAP אין חופש פעולה מבחינת הארכיטקטורה. הכל מוגדר מראש ורק צריך לממש את הפונקציונליות עצמה. המטרה היא להתמקד בקוד העסקי ולא במבנה הקוד והחלוקה שלו.

בנוסף, כל ניהול הגרסאות, העברה בין סביבות (DEV, QA, PROD) נעשות במתודולוגיה קבועה שמוטמעת בתוך המערכת. אי אפשר להעביר "פרוייקט" על דיסק און קי ולהעלות לשרת כמו בשפות אחרות.

לסיכום, על מנת לכתוב תוכנית ABAP מספיק להכיר את הפקודות של השפה, את הנהלים של כתיבת ABAP וכמה אלמנטים של UI. מי שתוהה איך המתכנת אמור להכיר את מאות אלפי האובייקטים (המכונים Business Object), היישויות במערכת והטבלאות אז גם לזה יש פתרון: מיישם ERP. תפקידו של המיישם להכיר את המודול הרלוונטי מכל הכיוונים והוא זה שמגדיר ומאפיין למתכנת לאילו אובייקטים לכתוב ואת מהלך התוכנית. למתכנת נשאר רק לממש את הקוד מה שמסביר למה מהנדסי תוכנה לא אוהבים ABAP…

כך נראית סביבת הפיתוח

SAP ABAP Workbench
SAP ABAP Workbench

העברת טופס לXML מAdobe Flex ActionScript3 לJava ובחזרה

כמתכנת FLEX פרילנסר עצמאי, מצאתי מקרים בהם הלקוח לא עובד בFramework מסודר לתקשורת Client-Server. במקרים כאלה לעיתים יש צורך לעשות Serialize לטופס ולהפוך אותו לפורמט גנרי כמו XML על מנת לשלוח אותו לשרת כלשהו (למשל J2EE Server) ע"י פרוטוקול כמו HTTP או SOAP Web Service. הנה פונקציה פשוטה שכתבתי שלוקחת טופס FLEX, מבצעת עליו סריקה רקורסיבית ושולפת את כל השדות שלו (TextInput) ומחזירה XML עם רשימת השדות והערכים שלהם.
כמו כן מצורף קוד בג'אווה שלוקח XML כזה והופך אותו לJava Bean ובמידה ובBean יש properties תואמים הם יקבלו את ערכי השדות. יש גם פונקציה הפוכה שלוקחת XML וממלאת את השדות בטופס FLEX.

יש להוסיף את הספריות האלה לקוד:

	import flash.utils.Dictionary;
	import mx.controls.TextInput;
	import mx.core.Container;

הנה הפונקציה (למעשה שתי פונקציות) שלוקחת טופס ומחזירה XML:

		public static function viewToXml(className:String, view:Container):String{
			var xml:XML = <bean class={className}></bean>;
			var xmlFinal:XML = addControlsToXml(xml, view);
			return '<?xml version="1.0" encoding="UTF-8"?>' + xmlFinal;
		}
		
		private static function addControlsToXml(xml:XML, view:Container):XML{
			var controls:Array = view.getChildren();
			for (var i:int; i<controls.length; i++){
				if (controls[i] is TextInput){
					var component:TextInput = controls[i] as TextInput;
					var child:XML = <property name={component.id}>{component.text}</property>;
					xml.appendChild(child);
				}
				if (controls[i] is Container){
					addControlsToXml(xml, controls[i] as Container);
				}
			}
			return xml;
		}

והפונקציה שמקבלת XML וממלאת את הטופס בהתאם:

		private static function xmlToView(props:Dictionary, view:Container):void{
			var controls:Array = view.getChildren();
			for (var i:int; i<controls.length; i++){
				if (controls[i] is TextInput){
					var component:TextInput = controls[i] as TextInput;
					if (props[component.id] != null){
						component.text = props[component.id];
					}
				}
				if (controls[i] is Container){
					xmlToView(props, controls[i] as Container);
				}
			}
		}

ועכשיו לקוד בג'אווה. תצטרכו להוסיף את הספריות הבאות:

import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

קבלת XML והפיכתו לJava Bean:

	public static Object xmlToBean(String xmlStr){
		DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder documentBuilder = null;
		try {
			documentBuilder = documentBuilderFactory.newDocumentBuilder();
			Document doc = documentBuilder.parse(new ByteArrayInputStream(xmlStr.getBytes("UTF-8")));
			XPath xpath = XPathFactory.newInstance().newXPath();
			Node bean = (Node)xpath.evaluate("//bean", doc, XPathConstants.NODE);
			if (bean != null){
				NamedNodeMap attributes = bean.getAttributes();
				Node cls = attributes.getNamedItem("class");
				String clsName = cls.getNodeValue();
				Object obj = Class.forName(clsName).newInstance();
				NodeList props = (NodeList)xpath.evaluate("//property", doc, XPathConstants.NODESET);
				Class cl = obj.getClass();
				for (int i=0; i<props.getLength(); i++){
					String propName = props.item(i).getAttributes().getNamedItem("name").getNodeValue();
					String propValue = props.item(i).getTextContent();
					String ch = propName.substring(0, 1).toUpperCase();
					String methodName = "set" + ch + propName.substring(1);
					Method[] methods = cl.getMethods();
					for (Method method : methods){
						if (method.getName().equals(methodName)){
							Class[] paramTypes = method.getParameterTypes();
							for (Class param : paramTypes){
								if (param.getName().equals("java.lang.String")){
									method.invoke(obj, propValue);
								}
								else if(param.getName().equals("int")){
									method.invoke(obj, Integer.valueOf(propValue));
								}
								else if(param.getName().equals("long")){
									method.invoke(obj, Long.valueOf(propValue));
								}
							}
						}
					}
				}
				return obj;
			}
		} catch (Exception e) {
			log.error(e);
		}
		return null;
	}

והחלק האחרון: לקחת Java Bean ולהפוך אותו לXML:

	public static String beanToXml(Object obj){
			DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder documentBuilder = null;
			try {
				documentBuilder = documentBuilderFactory.newDocumentBuilder();
			} catch (ParserConfigurationException e) {
				log.error(e);
			}
			Document doc = documentBuilder.newDocument();
			Element rootElement = doc.createElement("bean");
			rootElement.setAttribute("class", obj.getClass().getName());
			Method[] getters = obj.getClass().getMethods();
			for (Method getter : getters){
					if (getter.getName().indexOf("get") == 0)
					if (getter.getParameterTypes().length == 0)
					if (!getter.getName().equals("getClass")){
						StringBuffer prop = new StringBuffer(getter.getName().substring(3));
						String ch = prop.substring(0, 1).toLowerCase();
						prop.replace(0, 1, ch);
						
						Element propElement = doc.createElement("property");
						propElement.setAttribute("name", prop.toString());
						try {
							propElement.setTextContent(getter.invoke(obj).toString());
						} catch (Exception e) {
							e.printStackTrace();
						}
						rootElement.appendChild(propElement);
					}
			}
			doc.appendChild(rootElement);
			
			StringWriter stw = new StringWriter(); 
            Transformer serializer;
			try {
				serializer = TransformerFactory.newInstance().newTransformer();
				serializer.transform(new DOMSource(doc), new StreamResult(stw));
			} catch (Exception e) {
				log.error(e);
			}
            return stw.toString();
	}

איך לעבור מבחן וראיון מקצועי בחברת הי-טק

בין אם אתה שכיר ובין אם אתה פרילנסר עצמאי, הרבה פעמים תדרש לעבור מבחן מקצועי בתיכנות כדי לקבל את המשרה הנחשקת. להלן קובץ המלצות וכללים להצלחה במבחן קצועי בחברות הי-טק בתחום התוכנה.

השלב הראשון בהצלחה במבחן מקצועי בהי-טק מתחיל הרבה לפני המבחן. על מנת להגיע כמה שיותר מוכן, על המועמד לברר כמה שיותר פרטים אודות המצפה לו ולהתכונן בהתאם. במידה וזומנת למבחן מקצועי, הנה השאלות שכדאי לשאול את נציג הגיוס:

  1. כמה זמן יארך המבחן?
  2. מי מעביר את המבחן?
  3. האם המבחן הוא בעל פה במתכונת של ראיון, מבחן על דף או מבחן על מחשב?
  4. מהם נושאי המבחן בכלליות?

לא תמיד יתקבלו תשובות לכל השאלות. בעוד שמשך זמן המבחן הוא מידע שכמעט תמיד יימסר למועמד, הרי שנושאי המבחן הרבה פעמים יישארו חסויים. למרות זאת, יש חברות רבות שיגידו בכלליות מהם נושאי המבחן כגון: ג'אווה, הגיון, נושאי ידע כלליים וכו'.

ככלל, קיימים שלושה סוגים עיקריים של מבחנים:

  • מבחן בעל פה מול מראיין
  • כתיבת משימת קוד
  • קובץ של שאלות בדרך כלל אמריקאי

כעת נסקור כל אחד מסוגי הבחינות ונראה כיצד יש להתכונן אליהם ומה צריך לעשות כדי לעבור אותם בהצלחה.

מבחן בעל פה מול מראיין

במקרה זה, המבחן נערך ע"י מראיין אחד או יותר ששואל שאלות והמועמד מסביר בעל פה את התשובות. הראיון תמיד ייפתח בשאלה: "ספר לי על משהו מעניין שכתבת". לשאלה זו משקל חשוב ביותר בראיון והתשובה עליה במידה רבה קובעת את המשך התהליך. לכן חשוב מאוד להכין נושא שאפשר לדבר עליו בראיון. הנושא יכול להיות פרוייקט, פיצ'ר, מחקר, פתרון באג מסובך, אפילו פיתוח הדגמה (POC) או Design. צריך להיות מסוגל להציג את הנושא בלא יותר מ10 דקות בהנחה שלפניך מתכנת מקצועי שמעולם לא ראה את הפרוייקט. להלן הדגשים לבחירה והכנת נושא לראיון:

דבר על משהו שאתה שולט בו ב100%

היה בטוח שתשאל על הפרוייקט שאלות שונות עד כדי התעמקות בפרטים הקטנים. כעקרון, אין בעיה להציג משהו שלא פיתחת מאפס אלא שמישהו אחר פיתחת ואתה תחזקת או תקנת בו באגים (כדאי לציין זאת באגביות). זכור שגם המראיין רגיל לעבודה בצוות וברור לו שלא תמיד פיתחת הכל בעצמך. עם זאת, יש להקפיד לדבר על משהו שאתה שולט בו לפרטי פרטים ומכיר את הקוד והארכיטקטורה היטב.

בחר נושא עם מימוש מעניין שאפשר לפתח סביבו דיון

הצגת הודעת משתמש על המסך הוא לא משהו משמעותי למשל. עליך לבחור משהו שיכלול טכנולוגיה מעניינת, מימוש מורכב ורצוי בעל מאפיינים קלאסים כגון MVC, ירושה ותכנון OOP מורכב, שימוש מיוחד בטכנולוגיה. נושאים מעולים לדיון יהיו: פתרון של בעיית ביצועים, מימוש של Caching, Clustering, וכו', ארכיטקטורת שכבות כלשהי: DAO, ORM, אלגוריתמים כמו: עצי משחק, מכונות מצבים, פתרונות באמצעות תורת הגרפים, בעיות Multi Threading וסינכרון.

לא לדבר על דברים שהמראיין לא מסוגל לפתח סביבם שיחה

מטרת ההצגה של הפרוייקט הוא לפתח שיחה ולראות כיצד המועמד פותר בעיות, עד כמה הוא מבין את הנושא ומה יכולת הידע והניתוח שלו. לכן יש להקפיד לא להציג משהו שהמראיין לא יכול לקלוט בכמה דקות כמו שימוש בטכנולוגיה ובארכיטקטורה שלא מוכרת בתעשייה. בעבר נתקלתי במועמד שתיאר את העבודה שלו: "השתמשנו בSDC על מנת להתממשק לEWK וזאת על ידי התחברות בפרוטוקול RTM". אלו כמובן טכנולוגיות שפותחו באופן פנימי בחברה אבל לי כמראיין חיצוני זה לא אמר כלום. יש להקפיד לדבר במונחים וטרמינולוגיה שמוכרים לכולם ולא להשתמש בקודים פנימיים אליהם הורגלת בעבודתך הקודמת.

בחר משהו מהניסיון הרלוונטי ביותר

במידה ובעברך עבדת שנתיים בצבא ולאחר מכן 5 שנים במיקרוסופט היה בטוח שהמראיין מעוניין לשמוע על ניסיונך במיקרוסופט אפילו אם פיתחת דברים הרבה יותר מאתגרים בצבא. אם עבדת שנתיים בחברה למשחקי מחשב ושנתיים בחברה לפיתוח אתרים ואתה מועמד לחברה שמפתחת משחקי מחשב, יש כמובן להציג משהו מהניסיון שלך כמפתח משחקים. כנ"ל לגבי שפות תיכנות וטכנולוגיות. נסה להבין מה בקו"ח שלך משך את החברה לזמן אותך והכן פרוייקט לראיון שמתאים לפרופיל החברה.

הכן פרוייקט לגיבוי

לעיתים, המראיין לא יביע התעניינות במה שאתה מציג ותתבקש לדבר על משהו אחר. כדאי להכין גיבוי למקרה כזה ורצוי שהפרוייקט יהיה בעל אופי שונה מהראשון.

מה לגבי שאר השאלות?

לשאר השאלות קשה מאוד להתכונן כיוון שכל מראיין נוהג לשאול שאלות אחרות. דפוס שחוזר על עצמו הם שאלות קצרות באלגוריתמים פשוטים יחסית בעיקר סביב מבני נתונים. כדאי מאוד לחזור על הנושאים: רשימות מקושרות, עצים בינאריים, מערכים (מיון, חיפוש, מחיקה וכו'). במקרים רבים תינתן שאלה של 5-10 דקות בפתרון בעיה סביב הנושאים הללו כגון: פונקציה שממיינת מערך (כדאי לציין שיש כמה שיטות מיון), מציאת רשימה מקושרת מעגלית, הדפסת עץ בינארי עם ובלי רקורסיה וכו'. כדאי גם להכיר את רמות הסיבוכיות וההבדלים בין המבנים והאלגוריתמים השונים.

כתיבת משימת קוד

מבחנים אלו מעמתים את המועמד עם משימה שדומה באופייה לעבודה אמיתית. המטרה היא לראות כיצד המועמד מתמודד עם בעיה תכנותית, איזה סוג של פתרון הוא מציע, ומה רמת כתיבת הקוד. ברוב המקרים המבחן יתבצע על סביבת פיתוח סטנדרטית ומוכרת עם גישה לאינטרנט (אם כי לא תמיד) על מנת לדמות את המציאות היומיומית בחברה.

הכנה מוקדמת

ברוב המקרים תידרש לכתוב תוכנית console שמשתמשת בקלט פלט סטנדרטי בשורת פקודה. מעבר לזה רוב המימוש יכלול את רכיבי השפה הבסיסיים: מערכים, מבני נתונים, ניתוח Strings, וכו'. כדאי לחזור על דברים בסיסיים שאולי שכחת על מנת שלא לבזבז זמן יקר: פתיחת פרוייקט חדש בסביבת הפיתוח, פקודות קלט פלט למסך, הגדרת קלאסים מסוגים שונים: interface, abstract, החבילות המכילות את מבני הנתונים הנפוצים   (List, Hash) ועוד. עוד נושא קריטי להצלחה במבחן הוא: Design Patterns. DP הוא נושא שיחסית קל ללמוד ולזכור ומאידך שימוש נכון בDP משאיר רושם טוב ומקצועי. כדאי מאוד להכיר את התבניות של הGOF ולדעת איך להשתמש בהן.

להלן דגשים למבחן בכתיבת קוד:

אל תתעכב על קריאת האפיון ואל תרד לפרטים

הרבה פעמים האפיון יתפרס על כמה עמודים באנגלית ולקרוא אותו עד הסוף ולהבין אותו באופן מלא יכול לקחת 15-20 דקות. זהו זמן יקר בהתחשב בעובדה שרוב המבחנים אורכים כשעתיים (זמן מוגבל). כדאי לקרוא ברפרוף ולעבור לדוגמאות (בדרך כלל מופיעות במסמך) ולהבין בגדול מה מצפים. אף אחד לא יפסול אותך כי המבחן הדפיס "hello moshe" במקום ""hello david.

הקדש 10 דקות לתכנון הפתרון

מומלץ לסרטט את הפתרון על דף נפרד. להגדיר את המחלקות העיקריות והירושה, את המופעים העיקריים של האובייקטים והיחסים בינהם.

לעולם תתחיל מהגדרת כל המחלקות והפונקציות

יש להתחיל בהגדרת המחלקות והפונקציות ורק אחר כך לממש אותן. הסיבה היא שבמקרים רבים גם אם לא סיימת את כל המבחן (לפעמים אפילו לא מצפים ממך לסיים הכל), עדיין תוכל להציג את המבנה, הישויות, התכנון והמתודות השונות למרות שלא הכל מומש.

סטנדרטים מומלצים

חלק גדול מהמבחן הוא לבדוק האם המועמד משתמשת בBest Practices ובשיטות מקובלות ועד כמה הקוד שלו איכותי.

שמות מחלקות, משתנים, ומתודות

יש להקפיד על שמות בסטנדרט מקובל. מועמד שיקרא למשתנים שלו: a,b,c במקום: customer, person, manager יאבד נקודות במהירות. כנ"ל לגבי שימוש נכון באותיות גדולות וקטנות כפי שמקובל בשפה הרלוונטית.

תיעוד

לא כדאי להקדיש זמן לתיעוד. בדרך כלל הבוחן לא יסתכל על זה וזה גוזל זמן יקר. אפשר לכתוב הערה במקומות בהם הקוד מסתבך או לפני פונקציה שלא ברור למה היא נועדה. ברוב המקרים מספיק לתת שמות הגיוניים למשתנים ולפונקציות.

שימוש מושכל בפולימורפיזם

בג'אווה למשל, אפשר ליצור רשימה בכל אחת מהדרכים הבאות:

ArrayList list = new ArrayList ();

List list = new ArrayList();

List<String> list = new ArrayList<String>();

על אף שהתוצאה בשלושת המקרים תהיה זהה המקרה השלישי הוא הנכון ביותר. הרשימה מוגדרת כList שהינו interface כך שניתן להחליף את המימוש בקלות (למשל לLinkedList). הרשימה היא type safe כך שמובטח שתכיל רק אובייקטים מסוג String.

שימוש נכון בלולאות

נניח ויש לנו את הרשימה מהדוגמא הקודמת. כיצד נדפיס את אברי הרשימה?

For (int i=0; i<list.size(); i++)

System.out.println(list.get(i)):

(for String s : list)

System.out.println(list.get(i)):

כדאי להכיר את הלולאה for each (החל מג'אווה 1.5) ולהשתמש בה כשאפשר.

Design Patterns מומלצים

סטטיסטית, כמעט כל מרואיין שנשאל אילו DP הוא מכיר יענה Singleton או Factory. כדי להראות מקצועיות כדאי להכיר עוד כמה DP מלבד השניים המוכרים הללו. במבחנים המקצועיים יש כמה DP שיכולים להיות שימושיים, ואילו אחרים בדרך כלל לא יהיו רלוונטים. נהוג לחלק את רשימת הDP של הGOF לשלושה תתי רשימות: Creational Patterns, Structural Patterns, Behavioral Patterns. הStructural כמעט ולא רלוונטים למבחנים כיוון שבדרך כלל בשעתיים אי אפשר להגיע לרמות OO שמתאימות לדפוסים אלה. למעט Composite שכדאי להכיר כי בהרבה מבחנים מבקשים להגדיר מבנה בצורת עץ היררכי כלשהו.

הCreational מתאימים במקצת אם כי לרוב אין צורך בהם שוב בגלל שהקוד מצומצם למספר קטן של קלאסים.

הBehavioral הם המתאימים ביותר ורצוי לשנן אותם ולהשתמש בהם בעת הצורך.

מבחן אמריקאי

לרוב קשה להתכונן למבחן אמריקאי כיוון שאין לדעת אילו נושאים יופיעו ועל מה יהיה המיקוד. אבל ישנו דפוס שחוזר על עצמו לעיתים קרובות וכדאי להגיע מוכן אליו. כיוון שבכל תחום בעולם ההי-טק קיימים מאות טכנולוגיות שונות, ספריות, API, פלטפורמות וחבילות תוכנה אין כל כך טעם לבחון מועמד על טכנולוגיה מסויימת כיוון שקיים סיכוי טוב שאותו מועמד לא השתמש בטכנולוגיה זו ולכן לא יידע לענות על השאלות מה שלא מעיד על הידע והיכולות האמיתיות שלו. לכן נהוג לקחת את המכנה המשותף הנמוך ביותר שמצופה מכל מועמד להכיר וזה בדרך כלל החוקים של שפת התיכנות עצמה ונושאים סביב הליבה של הטכנולוגיה. הנושאים הנפוצים ביותר הנשאלים הם על: OOP וחוקי ירושה, פולימורפיזם, Up casting, down Casting, בעיות סינכרוניזציה וmulti Threading, מבני נתונים בסיסיים (רשימות, עצים בינארים), מערכים ומחרוזות, העברת פרמטרים By Value וby Reference, טיפול בexceptions כולל חוקי ההיררכיה, שאלות על פונקציות שונות במחלקות String וobject (רלוונטי לג'אווה ולדוט נט), Reflection, שימוש בbreak וcontinue ועוד.

בין הנושאים המתקדמים יותר אפשר למצוא: כוונון של הGC, JVM/CLR, סוגים שונים של Collections ודרך התנהגותם, מילות שמורות בשפה שנדיר להשתמש בהם, דקויות בין טיפוסי משתנים והמרות (int, long, double, float, char).

כללים לפיתוח אבטיפוס, הדגמה (Demo), ובדיקת התכנות (POC)

לאחרונה התחלתי לפתח אבטיפוס לרעיון מסויים למיזם חדש. מדובר על מוצר בתחום המערכות מידע ואני צריך הדגמה שתוכל להמחיש את הרעיון ולהוכיח היתכנות. משהו שאפשר להציג ללקוחות ולמשקיעים ואולי גם לשותפים פוטנציאליים. כיוון שזו לא הפעם הראשונה שאני כותב POC החלטתי לכתוב על זה פוסט בו אפרט כללים וטיפים לכתיבה נכונה.

קוד גנרי או פתרון זמני?

הנושא הראשון שצריך להחליט עליו הוא האם לפתח גרסה שתהווה בסיס למוצר המלא או שמא לפתח גרסה מינימלית שתעבור שכתוב? במחשבה ראשונה חבל לכתוב פעמיים ואם כבר מפתחים אבטיפוס עדיף להשקיע בו כדי לחסוך אחר כך. אך לדעתי זו לא גישה נכונה. להלן הסיבות למה לא להתייחס לאבטיפוס כפלטפורמה למוצר שלם:

  • לפיתוח אבטיפוס יש מטרה מסויימת. בדרך כלל זה להצגה בפני משקיעים או לקוחות. לרוב אנחנו לחוצים בזמן ובמשאבים ורצוי להתמקד במטרה. המטרה היא להגיע להדגמה שעובדת בצורה סבירה בתסריט מסויים. כל דבר מעבר לזה רק יעכב ויסית אותנו מהמטרה כך שעדיף לזנוח את המאמצים להפוך את ההדגמה לפלטפורמה להמשך.
  • לאחר סקר שוק מעמיק ולאחר כתיבת האפיונים הרבה פעמים מתגלה שמה שחשבנו בהתחלה הוא לא מה שנממש בסוף. חבל להשקיע זמן ומאמץ בפיתוח כשבסוף המוצר ייראה אחרת לגמרי.

כמובן שיש לבחון כל מקרה לגופו. יש מצבים בהם כדאי לפתח "כמו שצריך" במיוחד כאשר בטוחים בתצורה הסופית ואין ספק לגבי המשך הדרך.

להתמקד במינימום ההכרחי

כלל האצבע שמנחה את פיתוח האבטיפוס הוא התמקדות במטרה קצרת טווח. יש לזכור שהפיתוח יימשך תקופה קצרה, יעבדו עליו מספר מועט של אנשים (לפעמים זה רק אתה), ואין כוונות לתחזק אותו בעתיד. הנה טבלת ההמלצות לפיתוח אבטיפוס:

רכיב

המלצה

הערות בקוד

רק במקרים בהם יש כתיבה יוצאת דופן שעלולה להיות לא מובנת

Log

אין צורך. המוצר ממילא לא ירוץ בProduction והוא פשוט מספיק כדי לדבאג במקרה הצורך

Unit Tests

לאנשי הTDD ברור שצריך. לאחרים – מומלץ בדיקות פשוטות בלי Mocks ושאר סביבות מתוחכמות

Integration Tests

אין צורך

שימוש בFrameworks

האם להתשמש בפריימורקים כמו SPRING או Hibernate או שמא להסתפק בקוד "רגיל"? במידה ואתה בקיא לחלוטין בסביבה מסויימת והיא יכולה לחסוך זמן בפיתוח זה מומלץ. לעומת זאת, פריימוורק שמתכוונים ללמוד ולהתשמש בו במוצר הסופי לא כדאי להתעכב איתו עבור הPOC.

משתנים Hard coded

לא צריך להשאיר דברים hard coded כמו מחזרוזות בתוך פונקציות. עדיף להוציא הכל למשתני const. מצד שני אין צורך להוציא דברים החוצה (XML, DB, קובץ) אפשר לשנות את הקוד במידה ורוצים לערוך משהו

OOP

כללי כתיבה נכונה: חלוקה למחלקות, שכבות, וכו'. אין צורך להשתמש בDP מורכבים או בירושה מוגזמת. יש לזכור שהקוד כנראה יתפרס על פני מחלקות מועטות

אודות הבלוג הזה – מי אני

shlomo_schwarcz

מאז היותי ילד אני מתכנת בשפות שונות. בשנים האחרונות עסקתי בעבודות ובפרוייקטים רבים בתחום פיתוח תוכנה: החל מחברות ענק כמו SAP ואינפורמטיקה, דרך סטאטראפים כמו GigaSpaces ועד חברות תעשיתיות שונות כמו בתי זיקוק, פז ונטפים. תחום ההתמחות שלי הוא כל מה שקשור לטכנולוגיות ג'אווה: J2EE, EJB, JSP, Servles, JDBC, JNI, RMI, Spring, Hibernate, JSF, SWING. בנוסף עסקתי רבות גם בתחומי הסאפ השונים ובעיקר בNetWeaver, SAP Portal, WebDynpro, Visual Composer ושאר טכנולוגיות ג'אוואיות של SAP. וכמובן כדי להשלים את התמונה גם .C++, NET, C#, ASP מוכרים לי היטב.

עם השנים גיבשתי תובנות מעניינות על המקצוע אותם אני מתכוון לשתף עם קוראי הבלוג. בנוסף, אפרסם פה קודים ופרוייקטי קוד פתוח שאני כותב בזמני החופשי ומקרים מעניינים שאני נתקל בהם בזמן העבודה.

לסיום, אני פונה אליכם הקוראים. אני תמיד פתוח ליוזמות ורעיונות, שיתופי פעולה, מיזמים, סטארטאפים, שירותי יעוץ ועוד. אתם תמיד מוזמנים לפנות אליי עם כל רעיון או הצעה.

נשתמע,
שלמה שוורץ
shlomo@shefertech.com

אודות שלמה שוורץ

shlomo_schwarcz

בגיל 10 אבא שלי הביא הביתה את המחשב הראשון שלנו. זה היה אפל 2 עם מסך CRT שחור לבן (ירוק ליתר דיוק). למדתי לתכנת עליו בביסיק ומאז היה לי ברור שבעתיד אעסוק בתחום. בגיל התיכון התחלתי לתכנת ברצינות, בהתחלה בפסקל ואחר כך בC ובC++. היה זה בגיל 16 שמכרתי את התוכנה הראשונה שלי: פיתחתי תוכנת ניהול עבור חברת הובלות קטנה. הקוד נכתב בC על קומפיילר של בורלנד לwindows. הממשק נכתב בWIN16 API ורץ על Windows 3.11. האמצעים היו פרימיטיבים: ברוב הבתים לא היה אינטרנט נגיש ואת רוב התיכנות נאלצתי ללמוד מכמה ספרים ומקבצי הHELP שהגיעו עם הקומפיילר. לא ידעתי מה זה דאטהבייס וכל המידע נשמר בקבצי ASCII על הדיסק. התוכנה השתמשה ברשימות מקושרות ועצים בינארים כדי לאחסן את הרשומות בזיכרון וכל זאת על מחשב 486 מוגבל יחסית. אבל זה עבד, ואפילו עבד טוב.

לאחר הצבא התחלתי לעבוד בחברת סטראטאפ קטנה בשם טופטיר. זמן קצר לאחר מכן החברה נמכרה לSAP ב400 מליון דולר והמשכתי לעבוד בסאפ למעלה מ4 שנים. כשעזבתי את סאפ, הקמתי עסק משלי בשם "שפר מערכות" (ומכאן השם של האתר הזה) ועבדתי כמתכנת ויועץ פרילנסר עצמאי עבור ארגונים שונים. בין לקוחותיי: בתי הזיקוק, פז, הנוער העובד והלומד, GigaSpaces, מכללת אינטרביט, ועוד. לאחר מכן הצטרפתי לחברת דנשיר מערכות על מנת להקים את חטיבת הJava והNetWeaver ועמדתי בראש הקבוצה למעלה משנה כשאנחנו מבצעים פרוייקטים עבור חברות שונות: נטפים, בתי זיקוק, אוניברסיטת חיפה, מירס, תעשייה אווירית, דיאלוג ועוד. התחנה הבאה היתה חברת אינפורמטיקה שם מלאתי תפקיד של מתכנת בכיר – Principle Software Engineer.

ב2010 הקמתי חברת מגהסופט ומאז אני מכהן כמנכ"ל וכמובן ממשיך לפתח ולכתוב קוד במסגרת החברה. MegaSoft עוסקת בפיתוח עבור ארגונים, חברות הי-טק וסטארטאפים במגוון תחומים ובעיקר בג'אווה, Flex, מובייל ופלטפורמות קוד פתוח.

חוץ מזה אני תמיד מחפש את ההרפתקה הבאה ואשמח לקבל פניות, הצעות, הערות והארות.