April 2009 - Posts
Back to Basics – ASP.NET Page State Persister
Yesterday I was consulting
at
a client. The main
problems that the client
currently has are performance
issues. One of the problems
I found was the abuse of
ViewState without knowing
the consequences. I was
trying to reduce the ViewState for the pages and because of the
spaghetti code of the client’s application I had no chance in doing so.
I needed much more time to solve the problem with a proper solution.
Meanwhile, the client’s customer wanted results immediately so I used
the ASP.NET page state persiser to solve the matter currently and
instructed the developers how to start to solve their ViewState abuse.
What is ASP.NET Page State Persister?
ASP.NET supports a way to change the location in which the ViewState
data is stored. The default behavior to persist the ViewState is in a hidden
field. This behavior is enabled by the HiddenFieldPageState class. The
HiddenFieldPageState inherit from the PageStatePersister abstract class.
There is another implementation of the PageStatePersister which is the
SessionPageStatePersister. The SessionPageStatePersister enables us to
save the ViewState data in the session. Saving the ViewState in the session
consumes server resources (memory for example), can cause a lot of
troubles in web farms (using backend database for session can decrease
these problems) and makes troubles with session timeouts. In my situation
the change to SessionPageStatePersister is less painful because the client
uses only one server for the application and there aren’t a lot of users. But
even so you should always think before you make such a drastic change.
How to Use SessionPageStatePersister Instead of HiddenFieldPageState?
As written early, the default persister is the HiddenFieldPageState.
The way to change this behavior is very simple. In the web page you should
override the PageStatePersister property. The next example code show
how to do it:
protected override PageStatePersister PageStatePersister
{
get
{
return new SessionPageStatePersister(this);
}
}
If you want to enable this behavior to all your web application you
can create a base page that all your pages will inherit from. In that
base page you will put the previous shown code.
I built a small sample application that can show you how to use
SessionPageStatePersister. You can download it from here.
When using the example with the default behavior we get the
following ViewState:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"
value="/wEPDwUJNzE3NzE5MzAyD2QWAgIDD2QWAgIBDzwrAA0CAA8WBB4LXyFEYXRhQm91bmRnHgtfIUl0ZW
1Db3VudAIyZAwUKwABFgYeBFR5cGUZKwEeBE5hbWUFBEl0ZW0eCURhdGFGaWVsZAUBIRYCZg9kFmYCAQ9kFgJm
Dw8WAh4EVGV4dAUBMGRkAgIPZBYCZg8PFgIfBQUBMWRkAgMPZBYCZg8PFgIfBQUBMmRkAgQPZBYCZg8PFgIfBQ
UBM2RkAgUPZBYCZg8PFgIfBQUBNGRkAgYPZBYCZg8PFgIfBQUBNWRkAgcPZBYCZg8PFgIfBQUBNmRkAggPZBYCZ
g8PFgIfBQUBN2RkAgkPZBYCZg8PFgIfBQUBOGRkAgoPZBYCZg8PFgIfBQUBOWRkAgsPZBYCZg8PFgIfBQUCMTB
kZAIMD2QWAmYPDxYCHwUFAjExZGQCDQ9kFgJmDw8WAh8FBQIxMmRkAg4PZBYCZg8PFgIfBQUCMTNkZAIPD2QWA
mYPDxYCHwUFAjE0ZGQCEA9kFgJmDw8WAh8FBQIxNWRkAhEPZBYCZg8PFgIfBQUCMTZkZAISD2QWAmYPDxYCHwUF
AjE3ZGQCEw9kFgJmDw8WAh8FBQIxOGRkAhQPZBYCZg8PFgIfBQUCMTlkZAIVD2QWAmYPDxYCHwUFAjIwZGQCFg9
kFgJmDw8WAh8FBQIyMWRkAhcPZBYCZg8PFgIfBQUCMjJkZAIYD2QWAmYPDxYCHwUFAjIzZGQCGQ9kFgJmDw8WAh
8FBQIyNGRkAhoPZBYCZg8PFgIfBQUCMjVkZAIbD2QWAmYPDxYCHwUFAjI2ZGQCHA9kFgJmDw8WAh8FBQIyN2RkA
h0PZBYCZg8PFgIfBQUCMjhkZAIeD2QWAmYPDxYCHwUFAjI5ZGQCHw9kFgJmDw8WAh8FBQIzMGRkAiAPZBYCZg8P
FgIfBQUCMzFkZAIhD2QWAmYPDxYCHwUFAjMyZGQCIg9kFgJmDw8WAh8FBQIzM2RkAiMPZBYCZg8PFgIfBQUCMzR
kZAIkD2QWAmYPDxYCHwUFAjM1ZGQCJQ9kFgJmDw8WAh8FBQIzNmRkAiYPZBYCZg8PFgIfBQUCMzdkZAInD2QWAm
YPDxYCHwUFAjM4ZGQCKA9kFgJmDw8WAh8FBQIzOWRkAikPZBYCZg8PFgIfBQUCNDBkZAIqD2QWAmYPDxYCHwUFA
jQxZGQCKw9kFgJmDw8WAh8FBQI0MmRkAiwPZBYCZg8PFgIfBQUCNDNkZAItD2QWAmYPDxYCHwUFAjQ0ZGQCLg9k
FgJmDw8WAh8FBQI0NWRkAi8PZBYCZg8PFgIfBQUCNDZkZAIwD2QWAmYPDxYCHwUFAjQ3ZGQCMQ9kFgJmDw8WAh8
FBQI0OGRkAjIPZBYCZg8PFgIfBQUCNDlkZAIzDw8WAh4HVmlzaWJsZWhkZBgBBQpndkludGVnZXJzDzwrAAoBCA
IBZEvrLIgnB5+ESxkyXyxYmMJVv4GP" />
After using SessionPageStatePersister we get the following ViewState:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"
value="/wEPaA8FDzhjYjk2MjExNjlhMGUyZRgBBQpndkludGVnZXJzDzwrAAoBCAIBZIuK8e4SPfGzD0VbBhUyyjJeCfeW" />
Summary
Lets sum up, I explained today what is ASP.NET page state persister.
I also explained how to use the SessionPageStatePersister instead of
the default HiddenFieldPageState. This solution shouldn’t be done lightly.
You should think before you change the default behavior. In my situation
this solution will help the client currently but if the client wouldn’t
decrease the ViewState in the long run the solution will raise other
problems. Therefore, I made that change for now and instructed the
developers how to decrease the use of ViewState and in the long run
how to restore the HiddenFieldPageState persister.
Pro ADO.NET Data Services Book Review
Lately I’ve been reading a
lot.
One of the books that I read is
Pro ADO.NET Data Services -
Working with RESTful Data from
Apress which I’ll review in this post.
Review
The book isn’t long, its about 300 pages and has
four major parts:
- ADO.NET Data Service Fundamentals
- ADO.NET Data Services in the Real World
- ADO.NET Data Services from the Outside
- The Future of ADO.NET Data Services
The first part is written well and it gives a very thorough
understanding about the world of RESTful services and
ADO.NET data services in particularly. The part includes a lot
of material about the foundations of data services and how to use
them. I really liked the exercises that are spread all over the chapters
that help you to get started with the features that were discussed
early.
The second part was to short to my taste and only discussed
how to implement a data service alongside with an existing
legacy services. It shows how to build a new data service for
a customer service alongside of a legacy customer service which is
a legacy SOAP service. I really expected more full examples of
building applications with ADO.NET data services or a discussion
of were ADO.NET data services are fitting in the real world.
The third part included a coverage of a lot of subjects including
Ajax, Mashups, Silverlight and BizTalk. The information of the
Ajax and Silverlight chapters weren’t enough for my taste and
I think that the authors drilled down to much with the chapters
about Mashups and BizTalk. To be honest I read these two chapters
in a very fast manner because I’m very far away from these worlds.
The last part was a discussion about the future of ADO.NET data
services.
Summary
The book is very helpful especially in the first two parts. I think
that if you want to learn about ADO.NET data services this book
is not enough. In the internet there are a lot of materials that weren’t
covered by the book. Moreover I think that the book could be written as
a major part of a book about .NET RESTful services and not as a stand
alone book. My rating of the book is 3.5 stars out of 5.
Starting a New Journey
As I wrote in a previous post, I left
SRL Group, the company I worked
for in the last two and a half years.
Next week I’m starting a new
journey as a senior consultant and
.Net instructor in E4D Solutions company.
E4D Solutions company specializes
in providing training services,
consulting and developing in Microsoft
technologies, products and tools.
Every end is a new beginning…
Making Cross-Domain Ajax Requests for a Data Service
One problem that exists when
using ADO.NET data services is
cross-domain requests. For security
reasons, XMLHTTP requests don’t
allow cross-domain HTTP requests.
So what can we do if we want to
make an Ajax call for a data service
that isn’t located in our domain? this post will try to give a solution to this
problem.
Making a Cross-Domain Ajax Request for a Data Service
As stated early in the post’s start, for security reasons, XMLHTTP
requests don’t allow cross-domain HTTP requests. But sometimes we do
want to consume data services that aren’t located on our domain through
Ajax. The solution to making requests to a service outside our domain
is to implement a cross-domain proxy service. It means to create
a private service in your domain that will act as an intermediary between
your application and the data service. Your application will call the private
service and it will make the HTTP request to the data service.
How to Implement the Solution?
We can use WCF to create an Ajax-enabled endpoint using WebHttpBinding
and JSON serialization. One of the cons for such an implementation is
that we are using a traditional SOAP-based WCF service and not the fully
functionality of the data service.
Example
The following example will help you to understand how to implement the
solution proposed early. You can download the example code from
here.
Building the Data Service
We are going to use the same database that I used in my previous posts
in the data services series. The data service is a school service based upon
the following EDM mapping of entity framework:
The code for the data service is very simple and is only for the demonstration
of the post solution:
namespace SchoolDataService
{ public class SchoolDataService : DataService<SchoolEntities>
{ // This method is called only once to initialize service-wide policies.
public static void InitializeService(IDataServiceConfiguration config)
{ config.SetEntitySetAccessRule("*", EntitySetRights.All); config.SetServiceOperationAccessRule("*", ServiceOperationRights.All); }
}
}
Building the Cross-Domain Proxy Service
In order to build the proxy service we need to build service
contracts and data contracts for every operation and entities
that we want to expose from the consumed data service. In the
following example I’m going to implement the GetCourseByID
operation through the proxy service. The following code demonstrate
how to do so:
namespace ConsumerApplication
{ [DataContract]
public class CourseEntity
{ [DataMember]
public int CourseID { get; set; }
[DataMember]
public string Title { get; set; }
[DataMember]
public string Days { get; set; }
[DataMember]
public DateTime Time { get; set; }
[DataMember]
public string Location { get; set; }
[DataMember]
public int Credits { get; set; } }
[ServiceContract(Namespace = "mysite")]
[AspNetCompatibilityRequirements(
RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ProxyService
{ #region Members
private SchoolEntities _proxy = new SchoolEntities(
new Uri("http://localhost:2811/SchoolDataService.svc"));
#endregion
#region Service Methods
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
public CourseEntity GetCourseByID(int courseID)
{ var returningCourse = (from course in _proxy.Course
where course.CourseID == courseID
select course).ToList().First();
return new CourseEntity
{ CourseID = returningCourse.CourseID,
Credits = returningCourse.Credits,
Days = returningCourse.Days,
Location = returningCourse.Location,
Time = returningCourse.Time,
Title = returningCourse.Title
};
}
#endregion
}
}
Pay attention that in order to consume the service from client
side you need to configure the host to use the
WebScriptServiceHostFactory. To do so go to the service markup and
write the following code:
<%@ ServiceHost Language="C#" Debug="true"
Service="ConsumerApplication.ProxyService" CodeBehind="ProxyService.svc.cs"
Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory" %>
Building the Consuming Web Form
The following code demonstrate the consuming page of the
proxy service:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ConsumerApplication._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/ProxyService.svc" />
</Services>
</asp:ScriptManager>
<div id="content">
</div>
<script type="text/javascript"> 1:
2: function pageLoad() { 3: var proxy = new mysite.ProxyService();
4: proxy.GetCourseByID(1045, OnSuccess, onerror)
5: }
6:
7: function OnSuccess(result) { 8: var div = $get("content"); 9: div.innerText = result.Title;
10: }
11:
12: function OnError(result) { 13: // do something about the error
14: }
15:
16: pageLoad();
17:
</script>
</form>
</body>
</html>
Summary
Lets sum up, in today’s post I gave a solution for making cross-domain
Ajax requests to a data service. The solution has some cons like
using a traditional SOAP-based WCF service but it is ideal if you want
to consume public data service from other domains.
CodeProject
ADO.NET Entity Framework Extensions Library
As part of the MSDN Code Gallery you
can find the ADO.NET Entity Framework
Extensions library. The ADO.NET Entity
Framework Extensions includes
“utilities that make querying stored procedures,
creating typed results from DB data readers and
state tracking external data much easier in the
Entity Framework. A sample application demonstrates several patterns using these
utilities, including stored procedures with multiple result sets, materialization of
CLR types, and registering entities in the Entity Framework state manager” (the
description is taken from the library’s page).
The following utilities are included in the current release of the
ADO.NET Entity Framework Extensions library:
- Execution of store commands via the ObjectContext.
- Connection lifetime management.
- State management of entities from external sources.
- Materialization of arbitrary CLR types given a data reader or DB command.
- Stored procedure mapping:
- Multiple result sets.
- Column renames, polymorphic results and nested structures via the
materialization service.
- Getting and setting key values for entity references.
- Rewrite InvocationExpressions in LINQ queries and expressions.
You can download the library from here.
Enjoy!
Index Pages on My Blog
Lately, I received an e-mail from a reader of my blog which included
an advice to make an index for my post series. I took his advice and
made 3 index pages for the following subjects:
These index pages will be updated frequently whenever a new tutorial
post will be added. Also, I’m going to add more index pages in the
future for more post series.
Thanks Marcellus.
Enjoy!
Supporting Stored Procedures that Return Primitive Types in Entity Framework
One drawback of Entity
Framework designer is that it does
not generate code in the object
context for function imports
of stored procedures that return a
primitive type. This post will explain
how to achieve this functionality up until the designer will support it in the
next release of Entity Framework.
Supporting Stored Procedures that Return Primitive Types
As indicated in the post’s prolog the Entity Framework designer in V1 doesn’t
generate code for function imports of stored procedures that return a
primitive type. This makes the function import unavailable to use by the
object context of Entity Framework as opposed to other function import
mapping scenarios. We can work around this problem with the use of
EntityClient functionality.
The Example
In the example I’m going to use the following stored procedure which
returns the total budget of a school by the date range it gets as
parameters. The budget is stored as money type in the database.
CREATE PROCEDURE dbo.SchoolBudgetForDateRange
@StartDate DATETIME,
@EndDate DATETIME
AS
SET NOCOUNT ON;
SELECT SUM(Department.Budget) AS SchoolBudget
FROM Department
WHERE StartDate BETWEEN @StartDate AND @EndDate
Step 1
Add a FunctionImport for the stored procedure.
In the designer press the right mouse button and click on the
Add –> Function Import from the menu. The Add Function Import dialog
will be open and insert the following details:
Press OK to end this process. After doing step 1 we will have a FunctionImport
element in the CSDL but we won’t be able to use it from the object context
because no code will be generated for it.
Step 2
Use EntityClient to query the data. The following code shows how to
open a connection, create a stored procedure command, add parameters
to it and execute it using EntityClient.
static void Main(string[] args)
{
decimal result = 0;
using (var conn = new EntityConnection("Name = SchoolEntities"))
{
var cmd = conn.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "SchoolEntities.SchoolBudgetForDateRange";
cmd.Parameters.AddWithValue("StartDate", new DateTime(2009, 1, 1));
cmd.Parameters.AddWithValue("EndDate", DateTime.Now);
conn.Open();
result = Convert.ToDecimal(cmd.ExecuteScalar());
}
Console.WriteLine("The school budget is {0}", result);
Console.ReadLine();
}
As you can see it’s very close to using old fashion ADO.NET but
it works on the entity data model instead of a database.
Summary
Lets sum up, in the post I showed how we can use function imports of
stored procedures that return
primitive types. Probably we won’t
need to use this solution when the next release of
Entity Framework
will go out but meanwhile we will have to use
EntityClient as a
solution to this problem.
Entity Framework Mapping Helper
Entity Framework Mapping Helper
is a very useful tool that was
written by the Entity Framework
team and can help you to get started
with various of mappings scenarios.
“Entity Framework mapping helper lets you create sample mapping files
for the set of scenarios you are interested in. It’s a great tool for a deeper
understanding for how schema files are defined for complex mapping scenarios
in Entity Framework.” (The Entity Framework Mapping Helper description on
MSDN Code Gallery). You get inside of it the following mapping scenarios
examples:
- Inheritance – table per hierarchy (TPH), table per type (TPT),
table per concrete type (TPC) and a mix of these inheritance
types. - Entity Splitting – vertical splitting and horizontal splitting.
- Abstract types.
- Multiple entity set per type (MEST).
- Use of complex types.
- Association within EntitySet – one to one, one to many and
self association. - Association across EntitySets – one to one, one to many and
many to many. - Use of condition element – Boolean discriminator for TPH.
Every example is described in a graphical diagram and in a separated
schema files.
You can download it from MSDN Code Gallery in the following link:
Entity Framework Mapping Helper.
Enjoy.
Creating Complex Types in Entity Framework
The following post will
explain what are complex
types in Entity Framework
and how to use them.
What are Complex Types?
Complex types are a way to encapsulate a set of entity’s properties inside a
structure which isn’t an entity. You use them to organize properties into
structures that make your design more understandable. For example, you
can have a Customer entity which has properties that make an address.
You can arrange these properties in a Address complex type. Complex types
are a conceptual entities types. You build them in the CSDL and
map them to properties in the MSL.
Some points to be considered when using complex types:
- Complex types cannot exist without a parent entity or another
containing complex type. - Complex types are not supported in the current version of
Entity Framework’s designer. Using the Update Model form
Database feature will erase the manually changes of the complex
type. - Complex type properties cannot be null.
- You can’t use inheritance with complex types.
- A change to one property of a complex type will cause an update
to the entire complex type when SaveChanges method is called.
How to Use Complex Types in Code?
In the example I’m going to build a CourseDetails complex type inside
a Course entity. The recipe for building other complex types is the same.
Step 1
Open the model in a Xml editor and search for the CSDL part. Search
the entity that you want to build a complex type inside of it. In my example
the entity is Course:
<EntityType Name="Course">
<Key>
<PropertyRef Name="CourseID" />
</Key>
<Property Name="CourseID" Type="Int32" Nullable="false" />
<Property Name="Title" Type="String" Nullable="false" MaxLength="100" Unicode="true" FixedLength="false" />
<Property Name="Days" Type="String" Nullable="false" />
<Property Name="Time" Type="DateTime" Nullable="false" />
<Property Name="Location" Type="String" Nullable="true" />
<Property Name="Credits" Type="Int32" Nullable="false" />
<NavigationProperty Name="Department" Relationship="SchoolModel.FK_Course_Department" FromRole="Course" ToRole="Department" />
<NavigationProperty Name="Enrollment" Relationship="SchoolModel.FK_Enrollment_Course" FromRole="Course" ToRole="Enrollment" />
<NavigationProperty Name="Person" Relationship="SchoolModel.CourseInstructor" FromRole="Course" ToRole="Person" />
</EntityType>
Step 2
Copy the properties which will belong to the complex type and delete them
from the entity. Then, add a new property which will have the new complex
type’s type. The following is the new Course entity after adding the
CourseDetails complex type:
<EntityType Name="Course">
<Key>
<PropertyRef Name="CourseID" />
</Key>
<Property Name="CourseID" Type="Int32" Nullable="false" />
<Property Name="Title" Type="String" Nullable="false" MaxLength="100" Unicode="true" FixedLength="false" />
<Property Name="CourseDetails" Type="Self.CourseDetails" Nullable="false" />
<NavigationProperty Name="Department" Relationship="SchoolModel.FK_Course_Department" FromRole="Course" ToRole="Department" />
<NavigationProperty Name="Enrollment" Relationship="SchoolModel.FK_Enrollment_Course" FromRole="Course" ToRole="Enrollment" />
<NavigationProperty Name="Person" Relationship="SchoolModel.CourseInstructor" FromRole="Course" ToRole="Person" />
</EntityType>
Step 3
Add a new complex type to the CSDL and copy the saved properties to it.
<ComplexType Name="CourseDetails" >
<Property Name="Days" Type="String" Nullable="false" />
<Property Name="Time" Type="DateTime" Nullable="false" />
<Property Name="Location" Type="String" Nullable="true" />
<Property Name="Credits" Type="Int32" Nullable="false" />
</ComplexType>
Step 4
In the MSL, add a ComplexProperty inside the EntityTypeMapping of
your entity and insert the properties of the complex type inside of it.
<EntitySetMapping Name="Course">
<EntityTypeMapping TypeName="IsTypeOf(SchoolModel.Course)">
<MappingFragment StoreEntitySet="Course">
<ScalarProperty Name="CourseID" ColumnName="CourseID" />
<ScalarProperty Name="Title" ColumnName="Title" />
<ComplexProperty Name="CourseDetails" TypeName="SchoolModel.CourseDetails">
<ScalarProperty ColumnName="Days" Name="Days"/>
<ScalarProperty ColumnName="Time" Name="Time" />
<ScalarProperty ColumnName="Location" Name="Location" />
<ScalarProperty ColumnName="Credits" Name="Credits" />
</ComplexProperty>
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
And that’s it.
Step 5
Test the new mapping. The following code is a test program I wrote
to test the new CourseDetails complex type:
class Program
{
static void Main(string[] args)
{
using (SchoolEntities context = new SchoolEntities())
{
Course course = new Course
{
CourseDetails = new CourseDetails
{
Credits = 3,
Days = "MF",
Location = "Class A",
Time = DateTime.Now
},
Title = "New Course",
Department = context.Department.First()
};
context.AddToCourse(course);
context.SaveChanges();
var newCourse = (from c in context.Course
where c.Title == "New Course"
select c).First();
Console.WriteLine("{0}", newCourse.CourseDetails.Time);
Console.ReadLine();
}
}
}
The test program creates a new course and insert it to the
database. After that it retrieve that course and print to the output
the Time property which will hold the current time.
Summary
Lets sum up, today I explained what are complex types and how to
use them in Entity Framework. The use of complex types can help
you organize your design and to build CSDL structures which you
need. Pay attention to the restrictions that I wrote about they can have
an impact on your model’s design.
Who Develop the Developers?
Sometimes I find myself
wondering about the
title’s question.
During the years that I’m developing
software I found out that this
question isn’t trivial but holds a very
simple answer - you should. When I was
a junior developer, my team leader
gave me three books and said
that my first mission is to read these
books and then after three weeks he’ll
give me my first assignment. As you expect,
I read the books and got my first assignment.
But something was missing. I didn’t get any
help in the assignment even though I had a lot of questions.
After the first assignment (which I can still see it in the gov.il site even today)
I got my next assignment and so on but I felt that nobody could direct me about
how to be a good developer. During the next half a year I found myself reading
a lot, gaining knowledge and helping other junior developers in the company to
get started in a better way then I did. After a year I found myself as a team leader
and in that position I was expected to deliver quality products and in the project
time period. Then, I started to write simple guides to my team. I also encouraged
the team to learn and made a monthly meeting which one person should have lectured
about a subject he didn’t know. In that way the person was dedicated to learn the
subject and also could be a point of reference when somebody else in the team
needed to get an answer to a question in the subject. Also, Whenever a team
member needed my help, even though I had things to do, I always came and helped
him. It’s very hard to stop doing something and go help another person but it’s
for the team’s effort. These things helped to develop my team’s developing skills.
When I left my first company I brought the same methods to my new team.
I also started to tutor other developers in the new company and tutored inner
“courses” about ASP.NET. I’m still reading books and reading a lot of articles and
blogs to be updated and to read other people’s thoughts.
Why I wrote these things?
I think that the first steps are very crucial to a developer. Also, I think that in a
lot of companies developers are thrown to deep water (like I was) and
are expected to swim. I succeeded to swim but there are a lot of developers
that sink on the way. When I say sink I mean bad coding, bad design
and so on. I didn’t have someone like me to help me on my first steps but that
doesn’t mean that I can’t be that person to other developers. If I can do it
you also can. This is only a matter of patience and open-mindedness. You can
dedicate 30 minutes of tutoring a day and then to save up a lot of mess
tomorrow which you’ll probably handle. It’s in your hands.