زمانی که سیستم عامل های GUI مثل ویندوز به بازار آمدند، یکی از قسمتهای گرافیکی آنها AddressBar نام داشت که مسیر حرکت آنها را در فایل سیستم نشان میداد و در سیستم عاملهای متنی CLI با دستور cd یا pwd انجام میشد. بعدها در وب هم همین حرکت با نام BreadCrumb صورت گرفت که به عنوان مثال مسیر رسیدن به صفحهی یک محصول یا یک مقاله را نشان میداد. در یک پروژهی اندرویدی نیاز بود تا یک ساختار درختی را پیاده سازی کنم، ولی در برنامههای اندروید ایجاد یک درخت، کار هوشمندانه و مطلوبی نیست و روش کار به این صورت است که یک لیست از گروههای والد را نمایش داده و با انتخاب هر آیتم لیست به آیتمهای فرزند تغییر میکند. حالا مسئله این بود که کاربر باید مسیر حرکت خودش را بشناسد. به همین علت مجبور شدم یک BreadCrumb را برای آن طراحی کنم که در زیر تصویر آن را مشاهده میکنید.
از نکات جالب توجه در مورد این ماژول میتوان گفت که قابلیت این را دارد تا تصمیمات خود را بر اساس اندازههای مختلف صفحه نمایش بگیرد. به عنوان مثال اگر آیتمهای بالا بیشتر از سه عدد باشد و در صفحه جا نشود از یک مسیر جعلی استفاده میکند و همهی آیتمها با اندیس شماره 1 تا index-3 را درون یک آیتم با عنوان (...) قرار میدهد که من به آن میگویم مسیر جعلی. به عنوان نمونه مسیر تصویر بالا در صفحه جا شده است و نیازی به این کار دیده نشده است. ولی تصویر زیر از آن جا که مسیر، طول width صفحه نمایش رد کرده است، نیاز است تا چنین کاری انجام شود. موقعیکه کاربر آیتم ... را کلیک کند، مسیر باز شده و به محل index-3 حرکت میکند. یعنی دو مرحله به عقب باز میگردد.
نگاهی به کارکرد ماژول
قبل از توضیح در مورد سورس، اجازه دهید نحوهی استفاده از آن را ببینیم.
این سورس شامل دو کلاس است که سادهترین کلاس آن AndBreadCrumbItem میباشد که مشابه کلاس ListItem در بخش وب دات نت است و دو مقدار، یکی متن و دیگری Id را میگیرد:
سورس:
public class AndBreadCrumbItem { private int Id; private String diplayText; public AndBreadCrumbItem(int Id, String displayText) { this.Id=Id; this.diplayText=displayText; } public String getDiplayText() { return diplayText; } public void setDiplayText(String diplayText) { this.diplayText = diplayText; } public int getId() { return Id; } public void setId(int id) { Id = id; } }
به عنوان مثال میخواهیم یک breadcrumb را با مشخصات زیر بسازیم:
AndBreadCrumbItem itemhome=new AndBreadCrumbItem(0,"Home"); AndBreadCrumbItem itemproducts=new AndBreadCrumbItem(12,"Products"); AndBreadCrumbItem itemdigital=new AndBreadCrumbItem(15,"Digital"); AndBreadCrumbItem itemhdd=new AndBreadCrumbItem(56,"Hard Disk Drive");
AndBreadCrumb breadCrumb=new AndBreadCrumb(this); breadCrumb.AddNewItem(itemhome); breadCrumb.AddNewItem(itemproducts); breadCrumb.AddNewItem(itemdigital); breadCrumb.AddNewItem(itemhdd);
breadCumb.setContext(this);
پس از افزودن آیتم ها، تنظیمات زیر را اعمال نمایید:
LinearLayout layout=(LinearLayout)getActivity().findViewById(R.id.breadcumblayout); layout.setPadding(8, 8, 8, 8); breadCrumb.setLayout(layout); breadCrumb.SetTinyNextNodeImage(R.drawable.arrow); breadCrumb.setTextSize(25); breadCrumb.SetViewStyleId(R.drawable.list_item_style);
حال برای رسم آن متد UpdatePath را صدا میزنیم:
breadCrumb.UpdatePath();
الان اگر برنامه اجرا شود باید breadcrumb از چپ به راست رسم گردد. برای استفادههای فارسی، راست به چپ میتوانید از متد زیر استفاده کنید:
breadCrumb.setRTL(true);
در صورتیکه قصد دارید تنظیمات بیشتری چون رنگ متن، فونت متن و ... را روی هر المان اعمال کنید، از رویداد زیر استفاده کنید:
breadCrumb.setOnTextViewUpdate(new ITextViewUpdate() { @Override public TextView UpdateTextView(Context context, TextView tv) { tv.setTextColor(...); tv.setTypeface(...); return tv; } });
همچنین در صورتیکه میخواهید بدانید کاربر بر روی چه عنصری کلیک کرده است، از رویداد زیر استفاده کنید:
breadCumb.setOnClickListener(new IClickListener() { @Override public void onClick(int position, int Id) { //... } });
آخرین متد موجود که کمترین استفاده را دارد، متد SetNoResize است. در صورتیکه این متد با True مقداردهی گردد، عملیات تنظیم بر اساس صفحهی نمایش لغو میشود. این متد برای زمانی مناسب است که به عنوان مثال شما از یک HorozinalScrollView استفاده کرده باشید. در این حالت layout شما هیچ گاه به پایان نمیرسد و بهتر هست عملیات اضافه را لغو کنید.
نگاهی به سورس
کلاس زیر شامل بخشهای زیر است:
فیلدهای خصوصی
//=-=--=-=-=-=-=-=-=-=-=-=-=- Private Properties -=-=-=-=-=-=-=--=-=-= private List<AndBreadCrumbItem> items=null; private List<TextView> textViews; private int tinyNextNodeImage; private int viewStyleId; private Context context; private boolean RTL; private float textSize=20; private boolean noResize=false; LinearLayout layout; IClickListener clickListener; ITextViewUpdate textViewUpdate; LinearLayout.LayoutParams params ;
اینترفیسها هم با حرف I شروع و برای تعریف رویدادها ایجاد شدهاند. در ادامه از تعدادی متد get و Set برای مقدار دهی بعضی از فیلدهای خصوصی بالا استفاده شده است:
//=-=---=-=-=-=-- Constructor =--=-=-=-=-=--=-=- public AndBreadCrumb(Context context) { this.context=context; params = new LinearLayout.LayoutParams (LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); } //=-=-=--=--=-=-=-=-=-=-=-=- Public Properties --=-=-=-=-=-=--=-=-=-=-=-=- //each category would be added to create path public void AddNewItem(AndBreadCrumbItem item) { if(items==null) items=new ArrayList<>(); items.add(item); } // if you want a pointer or next node between categories or textviews public void SetTinyNextNodeImage(int resId) {this.tinyNextNodeImage=resId;} public void SetViewStyleId(int resId) {this.viewStyleId=resId;} public void setTextSize(float textSize) {this.textSize = textSize;} public boolean isRTL() { return RTL; } public void setRTL(boolean RTL) { this.RTL = RTL; } public void setLayout(LinearLayout layout) { this.layout = layout; } public void setContext(Context context) { this.context = context; } public boolean isNoResize() { return noResize; } public void setNoResize(boolean noResize) { this.noResize = noResize; }
بعد از آن به متدهای خصوصی میرسیم که متد زیر، متد اصلی ما برای ساخت breadcrumb است:
//primary method for render objects on layout private void DrawPath() { //stop here if essentail elements aren't present if (items == null) return ; if (layout == null) return; if (items.size() == 0) return; //we need to get size of layout,so we use the post method to run this thread when ui is ready layout.post(new Runnable() { @Override public void run() { //textviews created here one by one int position = 0; textViews = new ArrayList<>(); for (AndBreadCrumbItem item : items) { TextView tv = MakeTextView(position, item.getId()); tv.setText(item.getDiplayText()); textViews.add(tv); position++; } //add textviews on layout AddTextViewsOnLayout(); //we dont manage resizing anymore if(isNoResize()) return; //run this code after textviews Added to get widths of them TextView last_tv=textViews.get(textViews.size()-1); last_tv.post(new Runnable() { @Override public void run() { //define width of each textview depend on screen width BatchSizeOperation(); } }); } }); }
TextView tv=new TextView(this); tv.getWidth(); //return 0 layout.add(tv); tv.getWidth(); //return 0
TextView tv=new TextView(this); tv.post(new Runnable() { @Override public void run() { tv.getWidth(); //return x } });
باز میگردیم به متد DrawPath و داخل متد post
در اولین خط این پروسه به ازای هر آیتم، یک TextView توسط متد MakeTextView ساخته میشود که شامل کد زیر است:
private TextView MakeTextView(final int position, final int Id) { //settings for cumbs TextView tv=new TextView(this.context); tv.setEllipsize(TextUtils.TruncateAt.END); tv.setSingleLine(true); tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); tv.setBackgroundResource(viewStyleId); /*call custom event - this event will be fired when user click on one of textviews and returns position of textview and value that user sat as id */ tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SetPosition(position); clickListener.onClick(position, Id); } }); //if user wants to update each textviews if(textViewUpdate!=null) tv=textViewUpdate.UpdateTextView(context,tv); if(isRTL()) tv.setRotationY(180); return tv; }
در خطوط اولیه، یک Textview ساخته و متد Ellipsize را با Truncate.END مقداردهی مینماید. این مقدار دهی باعث میشود اگر متن، در Textview جا نشد، ادامهی آن با ... مشخص شود. در خط بعدی Textview را تک خطه معرفی میکنیم. در خط بعدی اندازهی قلم را بر اساس آنچه کاربر مشخص کرده است، تغییر میدهیم و بعد هم استایل را برای آن مقداردهی میکنیم. بعد از آن رویداد کلیک را برای آن مشخص میکنیم تا اگر کاربر بر روی آن کلیک کرد، رویداد اختصاصی خودمان را فراخوانی کنیم.
در خط بعدی اگر rtl با true مقدار دهی شده باشد، textview را حول محور Y چرخش میدهد تا برای زبانهای راست به چپ چون فارسی آماده گردد و در نهایت Textview ساخته شده و به سمت متد DrawPath باز میگرداند.
بعد از ساخته شدن TextViewها، وقت آن است که به Layout اضافه شوند که وظیفهی اینکار بر عهدهی متد AddTextViewOnLayout است:
//this method calling by everywhere to needs add textviews on the layout like master method :drawpath private void AddTextViewsOnLayout() { //prepare layout //remove everything on layout for recreate it layout.removeAllViews(); layout.setOrientation(LinearLayout.HORIZONTAL); layout.setVerticalGravity(Gravity.CENTER_VERTICAL); if(isRTL()) layout.setRotationY(180); //add textviews one by one int position=0; for (TextView tv:textViews) { layout.addView(tv,params); //add next node image between textviews if user defined a next node image if(tinyNextNodeImage>0) if(position<(textViews.size()-1)) { layout.addView(GetNodeImage(), params); position++; } } }
تا به اینجا کار چیدمان به ترتیب انجام شده است ولی از آنجا که اندازهی Layout در هر گوشی و در دو حالت حالت افقی یا عمودی نگه داشتن گوشی متفاوت است، نمیتوان به این چینش اعتماد کرد که به چه نحوی عناصر نمایش داده خواهند شد و این مشکل توسط متد BatchSizeOperation (تغییر اندازه دسته جمعی) حل میگردد. در اینجا هم باز متد post به آخرین textview اضافه شده است. به این علت که موقعیکه همهی textviewها در ui جا خوش کردند، بتوانیم به خاصیتهای ui آنها دستیابی داشته باشیم. حالا بعد از ترسیم باید اندازه آنها را اصلاح کنیم. قدم به قدم متد BatchSizeOperation را بررسی میکنیم:
//set textview width depend on screen width private void BatchSizeOperation() { //get width of next node between cumbs Bitmap tinyBmap = BitmapFactory.decodeResource(context.getResources(), tinyNextNodeImage); int tinysize=tinyBmap.getWidth(); //get sum of nodes tinysize*=(textViews.size()-1); ... }
//get width size of screen(layout is screen here) int screenWidth=GetLayoutWidthSize(); //get sum of arrows and cumbs width int sumtvs=tinysize; for (TextView tv : textViews) { int width=tv.getWidth(); sumtvs += width; }
private int GetLayoutWidthSize() { int width=layout.getWidth(); int padding=layout.getPaddingLeft()+layout.getPaddingRight(); width-=padding; return width; }
private void BatchSizeOperation() { .... //if sum of cumbs is less than screen size the state is good so return same old textviews if(sumtvs<screenWidth) return ; if(textViews.size()>3) { //make fake path MakeFakePath(); //clear layout and add textviews again AddTextViewsOnLayout(); } //get free space without next nodes -> and spilt rest of space to textviews count to get space for each textview int freespace =screenWidth-tinysize; int each_width=freespace/textViews.size(); //some elements have less than each_width,so we should leave size them and calculate more space again int view_count=0; for (TextView tv:textViews) { if (tv.getWidth()<=each_width) freespace=freespace-tv.getWidth(); else view_count++; } if (view_count==0) return; each_width=freespace/view_count; for (TextView tv:textViews) { if (tv.getWidth()>each_width) tv.setWidth(each_width); } }
اگر آیتمها بیشتر از سه عدد باشند، میتوانیم از حالت مسیر جعلی استفاده کنیم که توسط متد MakeFakePath انجام میشود. البته بعد از آن هم باید دوباره viewها را چینش کنیم تا مسیر جدید ترسیم گردد، چون ممکن است بعد از آن باز هم جا نباشد یا آیتمها بیشتر از سه عدد نیستند. در این حالت، حداقل کاری که میتوانیم انجام دهیم این است که فضای موجود را بین آنها تقسیم کنیم تا همهی کاسه، کوزهها سر آیتم آخر نشکند و متنش به ... تغییر یابد و حداقل از هر آیتم، مقداری از متن اصلی نمایش داده شود. پس میانگین فضای موجود را گرفته و بر تعداد المانها تقسیم میکنیم. البته این را هم باید در نظر گرفت که در تقسیم بندی، بعضی آیتمها آن مقدار پهنا را نیاز ندارند و با پهنای کمتر هم میشود کل متنشان را نشان داد. پس یک کار اضافهتر این است که مقدار پهنای اضافی آنها را هم حساب کنیم و فقط آیتمهایی را پهنا دهیم که به مقدار بیشتری از این میانگین احتیاج دارند. در اینجا کار به پایان میرسد و مسیر نمایش داده میشود.
نحوهی کارکرد متد MakeFakePath بدین صورت است که 4 عدد TextView را ایجاد کرده که المانهای با اندیس 0 و 2 و 3 به صورت نرمال و عادی ایجاد شده و همان کارکرد سابق را دارند. ولی المان شماره دو با اندیس 1 با متن ... نمایندهی آیتمهای میانی است و رویدادکلیک آن به شکل زیر تحریف یافته است:
//if elements are so much(mor than 3),we make a fake path to decrease elements private void MakeFakePath() { //we make 4 new elements that index 1 is fake element and has a rest of real path in its heart //when user click on it,path would be opened textViews=new ArrayList<>(4); TextView[] tvs=new TextView[4]; int[] positions= {0,items.size()-3,items.size()-2,items.size()-1}; for (int i=0;i<4;i++) { //request for new textviews tvs[i]=MakeTextView(positions[i],items.get(positions[i]).getId()); if(i!=1) tvs[i].setText(items.get(positions[i]).getDiplayText()); else { tvs[i].setText("..."); //override click event and change it to part of code to open real path by call setposition method and redraw path tvs[i].setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int pos = items.size() - 3; int id = items.get(pos).getId(); SetPosition(items.size() - 3); clickListener.onClick(pos, id); } }); } textViews.add(tvs[i]); } }
WTF is a personal information dashboard for your terminal, developed for those who spend most of their day in the command line.
وب سایت FeedSpot
سایت آموزشی: C# Station
در چه برنامههایی استفاده از بانکهای اطلاعاتی NoSQL مناسبتر است؟
1) برنامههای مدیریت محتوا
2) کاتالوگهای محصولات (هر برنامهای با تعدادی شیء و خصوصا متادیتای متغیر)
3) شبکههای اجتماعی
4) Big Data
5) سایر
1) برنامههای مدیریت محتوا
بانکهای اطلاعاتی NoSQL سندگرا، جهت تهیه برنامههای مدیریت محتوا، بسیار مناسب هستند. در این نوع برنامهها، یک سری محتوا که دارای متادیتایی هستند، ذخیره خواهند شد. این متادیتاها مانند نوع، گروه و هر نوع خاصیت دیگری، میتواند باشند. برای ذخیره سازی این نوع اطلاعات، جفتهای key-value بسیار خوب عمل میکنند. همچنین در بانکهای اطلاعاتی سندگرای NoSQL، با استفاده از مفهوم برچسبها، امکان الصاق فایلهای متناظری به اسناد پیش بینی شدهاست. همانطور که در قسمت قبل نیز ذکر شد، در Document stores، نگارشهای قدیمی اسناد نیز حفظ میشوند. به این ترتیب، این خاصیت و توانمندی توکار، امکان دسترسی به نگارشهای مختلف یک محتوای خاص را به سادگی میسر میسازد. به علاوه اکثر Document stores امکان دسترسی به این مستندات را به کمک URLها و REST API، به صورت خودکار فراهم میسازند.
برای نمونه به CouchDB، عنوان Web database نیز داده شده است؛ از این جهت که یک برنامه وب را میتوان داخل بانک اطلاعاتی آن قرار داد. در اینجا منظور از برنامه وب، یک وب سایت قابل دسترسی از طریق URLها است و نه برنامههای سازمانی وب. برای نمونه ساختاری شبیه به برنامه معروف EverNote را میتوان داخل این نوع بانکهای اطلاعاتی به سادگی ایجاد کرد (خود بانک اطلاعاتی تشکیل شده است از یک وب سرور که REST API را پشتیبانی کرده و امکان دسترسی به اسناد را بدون نیاز به کدنویسی اضافهتری، از طریق URLها و HTTP Verbs استاندارد مهیا میکند).
2) کاتالوگهای محصولات
محصولات در یک کاتالوگ، ویژگیهای مشابه یکسان فراوانی دارند؛ اما تعدادی از این محصولات، دارای ویژگیهایی خاص و منحصربفردی نیز میباشند.
مثلا یک شیء محصول را درنظر بگیرید که دارای خواص مشترک و یکسان شماره، نام، توضیحات و قیمت است. اما بعضی از محصولات، بسته به ردهی خاصی که دارند، دارای ویژگیهای خاصی مانند قدرت تفکیک، رنگ، سرعت و غیره نیز هستند که از هر گروه، به گروه دیگری متغیر است.
برای مدیریت یک چنین نیازی، هر دو گروه key-value stores و wide column stores بانکهای اطلاعاتی NoSQL مناسب هستند؛ از این جهت که در یک key-value store نیازی به تعریف هیچ نوع ساختار خاصی، در ابتدای کار نیست و این ساختار میتواند از هر رکورد، به رکورد دیگری متفاوت باشد.
یا برای نمونه، یک برنامه فرم ساز را درنظر بگیرید که هر فرم آن، هر چند دارای یک سری خواص ثابت مانند نام، گروه و امثال آن است، اما هر کدام دارای فیلدهای تشکیل دهنده متفاوتی نیز میباشد. به این ترتیب با استفاده از key-value stores، دیگری نیازی به نگران بودن در مورد نحوه مدیریت اسکیمای متغیر مورد نیاز، نخواهد بود.
3) شبکههای اجتماعی
همانطور که در قسمت قبل نیز بحث شد، نوع خاص Graph databases برای کاربردهای برنامههای شبکههای اجتماعی و ردیابی تغییرات آنها بسیار مفید و کارآ هستند. برای مثال در یک شبکه افراد دارای تعدادی دنبال کننده هستند؛ عضو گروههای مختلف میباشند، در قسمتهای مختلفی نظر و مطلب ارسال میکنند. در اینجا، اشیاء نسبت به یکدیگر روابط مختلفی دارند. با استفاده از Graph databases، تشکیل روابط self-joins و تو در تو و بسیاری از روشهای خاص، مانند روابط many-to-many که در بانکهای اطلاعاتی رابطهای با تمهیدات ویژهای قابل تشکیل هستند، با سهولت بهتری مدیریت خواهند شد.
4) Big Data
الگوریتم MapReduce، برای کار با حجم دادههای عظیم، طراحی شده است و در این بین، بانکهای اطلاعاتی Wide column store (که در قسمت قبل بررسی شدند) و یا حتی Key-value store (مانند Amazon DynamoDB) بیشتر کاربرد دارند. در سناریوهای دادههای عظیم، واژههای Hadoop و Hbase دنیای NoSQL را زیاد خواهید شنید. Hadoop نسخه سورس باز MapReduce گوگل است و Hbase نیز نسخه سورس باز BigTable گوگل میباشد. مفاهیم پایهای Sharding و فایل سیستمهای Append-only (با سرعت بالای نوشتن) نیز به مدیریت BigData کمک میکنند.
در اینجا بحث مهم، خواندن اطلاعات و آنالیز آنها است و نه تهیه برنامههای معروف CRUD. بسیاری از اعمال آماری و ریاضی مورد نیاز بر روی دادههای عظیم، نیازی به اسکیمای از پیش مشخص شده بانکهای اطلاعاتی رابطهای را ندارند و یا در اینجا قابلیتهای نوشتن کوئریهای پیچیده نیز آنچنان مهم نیستند.
5) سایر کاربردها
- هر سیستمی که اطلاعات Log مانند را تولید میکند. منظور از Log، اطلاعاتی است که در حین رخداد خاصی تولید میشوند. عموما مرسوم است که این نوع اطلاعات را در فایلها، بجای بانک اطلاعاتی ذخیره کرد. بنابراین مدیریت این نوع فایلها توسط بانکهای اطلاعاتی NoSQL، قابلیت انجام امور آماری را بر روی آنها سادهتر خواهد ساخت.
- مدیریت اطلاعات برنامههایی مانند سیستمهای EMail.
و در چه برنامههایی استفاده از بانکهای اطلاعاتی رابطهای مناسبتر است؟
اگر تا اینجا به مزایای استفاده از بانکهای اطلاعاتی NoSQL اشاره شد، بدین معنا نیست که بانکهای اطلاعاتی رابطهای، منسوخ شدهاند یا دیگر قدر و قیمتی ندارند. واقعیت این است که هنوز بازه وسیعی از کاربردها را میتوان به کمک بانکهای اطلاعاتی رابطهای بهتر از بانکهای اطلاعاتی NoSQL مدیریت کرد. این کاربردها و مزیتها در 5 گروه عمده خلاصه میشوند:
1) نیاز به تراکنشها
2) اسکیمای پیش فرض
3) برنامههای LOB یا Line of business applications
4) زبانهای کوئری نویسی پیشرفته
5) نیاز به امکانات گزارشگیری پیشرفته
1) نیاز به تراکنشها
در سیستمهای تجاری عمومی، نیاز به پیاده سازی مفهوم ACID که در قسمتهای قبل به آن پرداخته شد، مانند Atomic transactions وجود دارد. Atomic transaction به زبان ساده به این معنا است که سیستم قادر است چندین دستور را در قالب یک گروه و در طی یک مرحله، به بانک اطلاعاتی اعمال کند و اگر یکی از این دستورات گروه در حال اعمال، با شکست مواجه شد، باید کل تراکنش برگشت خورده و امنیت کار تضمین گردد. در غیراینصورت با یک سیستم غیر هماهنگ مواجه خواهیم شد.
و همانطور که پیشتر نیز عنوان شد، سیستمهای NoSQL، مبنای کار را بر اساس «عاقبت یک دست شدن» اطلاعات قرار دادهاند؛ تا دسترسی پذیری به آنها افزایش یافته و سرعت عملیات به این نحو بهبود یابد. در این نوع سیستمها تضمینی در مورد ACID وجود ندارد.
2) اسکیمای پیش فرض
پروسههای متداول، دارای ساختاری مشخص و معمولی هستند. زیرا طراحی اولیه یک پروسه، بر مبنای مجموعهای از اطلاعات است که همیشه باید وجود داشته باشند و اگر همانند بحث کاتالوگهای محصولات، نیاز به متادیتای متغیر نباشد، ساختار و اسکیمای یک پروسه، از ابتدای طراحی آن مشخص میباشد.
و ... تمام اینها را به خوبی میتوان توسط بانکهای اطلاعاتی رابطهای، با تعریف یک اسکیمای مشخص، مدیریت کرد.
3) برنامههای LOB یا Line of business applications
در برنامههای تجاری متداول، طراحی طرحبندی فرمهای برنامه یا انقیاد دادهها، بر اساس یک اسکیما و ساختار مشخص صورت میگیرد. بدون داشتن یک اسکیمای مشخص، امکان تعاریف انقیاد دادهها به صورت strongly typed وجود نخواهد داشت. همچنین کل مفهوم Object relational mapping و ORMهای مختلف نیز بر اساس وجود یک اسکیمای مشخص و از پیش تعیین شده کار میکند. بنابراین بانکهای اطلاعاتی رابطهای، انتخاب بسیار مناسبی برای تهیه برنامههای تجاری روزمره هستند.
4) زبانهای کوئری نویسی پیشرفته
همانطور که عنوان شد برای تهیه کوئری بر روی اغلب بانکهای اطلاعاتی NoSQL، باید توسط یک برنامه ثانویه، کار پیاده سازی الگوریتم Map Reduce را انجام داد. هر چند تعدادی از این نوع بانکهای اطلاعاتی به صورت توکار دارای موتور MapReduce هستند، اما بسیاری از آنها خیر. به همین جهت برای تهیه کوئریهای متداول، کار پیاده سازی این برنامههای ثانویه مشکل خواهد بود. به این ترتیب نوشتن Ad Hoc queries و گزارشگیری بسیار مشکل میشوند.
علاوه بر امکانات خوب کوئری گرفتن در بانکهای اطلاعاتی رابطهای، این کوئریها در زمان اجرا نیز بر اساس اسکیمای موجود، بسیار بهینه و با سرعت بالا اجرا میشوند. قابلیتی که رسیدن به آن در بانکهای اطلاعاتی با اسکیمای متغیر، کار سادهای نیست و باید آنرا با کدنویسی شخصی بهینه کرد. البته اگر تعداد این نوع برنامههای ثانویه که به آنها imperative query در مقابل declarative query بانکهای رابطهای میگویند، کم باشد، شاید یکبار نوشتن و بارها استفاده کردن از آنها اهمیتی نداشته باشد؛ در غیراینصورت تبدیل به یک عذاب خواهد شد.
5) نیاز به امکانات گزارشگیری پیشرفته
گزارشگیرهای برنامههای تجاری نیز بر اساس یک ساختار و اسکیمای مشخص به کمک قابلیتهای پیشرفته کوئری نویسی بانکهای اطلاعاتی رابطهای به سادگی قابل تهیه هستند. برای تهیه گزارشاتی که قابلیت چاپ مناسبی را داشته باشند، محل قرارگیری فیلدهای مختلف در صفحه مهم هستند و با متغیر بودن آنها، قابلیت طراحی از پیش آنها را از دست خواهیم داد. در این حالت با اسکیمای متغیر، حداکثر بتوان یک dump از اطلاعات را به صورت ستونی نمایش داد.
بنابراین به صورت خلاصه، بانکهای اطلاعاتی رابطهای، جهت مدیریت کارهای روزمره تجاری اغلب شرکتها، بسیار ضروری و جزو مسایل پایهای بهشمار میروند و به این زودیها هم قرار نیست با نمونهی دیگری جایگزین شوند.
مدیریت سفارشی سطوح دسترسی کاربران در MVC
ممنون بابت آموزش خوبتون امکانش هست یه کم در باره این بخش از صحبت تون و نحوه پیاده سازیش بیشتر توضیح بدید؟
[ توجه داشته باشید که کنترل مجوز برای بررسی وجود مجوز در بخشهای کوچکتر هم مانند اکشنها و ... میتونه در نظر گرفته بشه . ]
با توجه به آخرین نگارشهای موجود Angular و React، انتخاب شما برای انجام یک پروژه بزرگ کدام است؟
When a developer switches context, they must first disengage from the task at hand and then shift their focus to the new task. This whole process takes time and can drain devs mentally. It takes a developer 25 minutes to refocus after a context switch.